Skip to content

Templating system

ohory edited this page Sep 11, 2012 · 4 revisions

Definition

The core.js templating system takes place in the controllers. It allows you to evaluate HTML templates with John Resig micro-templating in client-side or ejs in server-side (Node.js). This system is capable to include a template as a component of another template to easily structure and factorize your code.

HTML templates

The template syntaxe is quite simple. It’s basic html with some javascript variables, conditions and loops.

Variable

You can print a variable in your template using the tag {%=variableName%} :

<script id="tmpl_feed_article" type="text/html">  
   <div class="article">  
      <div id="title"><h3>{%=title%}</h3></div> 
      {%=text%}
   </div> 
</script>

Condition

All javascript conditional structures are availables in the templates. You can use if/elseif/else or switch/case indifferently. For example:

<script id="tmpl_feed_article" type="text/html">  
   <div class="article">  
      ...  
      {% if(nbComments > 0) { %}  
      <span>{%=nbComments%} comments</span>  
      {% } else { %}  
      <span>no comment</span>  
      {% } %}  
   </div>
</script>

You can also use ternary operation and directly output the result of the operation in the template:

<script id="tmpl_feed_article" type="text/html">  
   <div class="article">  
      ...  
      <span>{%=(nbComments > 0) ? nbComments + " comments" : "no comment"%}</span>  
   </div>  
</script>

Loop

Same as conditions, all looping structures are availables. For example you can use a for loop:

<script id="tmpl_feed_article" type="text/html">  
   <div class="article">  
      ...  
      <ol class="comments">  
         {% for(var i=0, len=comments.length; i < len; i++) { %}  
         <li>{%=comments[i]%}</li>
         {% } %}  
      </ol>
   </div>
</script>

Component inclusion

Inclusion is a feature provided by the core.js. It simply requests to evaluate another template and returns generated html in the current template. You can also pass data to the included template.

<script id="tmpl_feed_article" type="text/html">  
   <div class="article">  
      ...  
      {%-component('comments', 'feed', comments)%}  
   </div>
</script>  
  
<script id="tmpl_feed_comments" type="text/html">  
   <ol class="comments">  
      {% for(var i=0, len=comments.length; i < len; i++) { %}  
      <li>{%=comments[i]%}</li>  
      {% } %}  
   </ol>
</script>

Here the "feed" parameter is optional because both template are manage by the same controller. So you can just write {%-component('comments', comments)%}.

Template name

As you may have seen templates are included in a <script type="text/html"></script>. This script takes an id that allows the core.js to retrieve it in the source. The id is in fact the name of the template and must be formatted as it: "tmpl_ctrlNameactionName" or "tmplcustomName" if there's no action defined. You can find details about what is an action in the second part below.

Javascript implementation

Templating execution

In the core.js, templates are considered as actions which must be execute. There’s 2 ways to call this execution according to the javascript execution context. In the browser-side, you can call it inside a view using app.exec() function. In the server-side (Node.js), this execution is directly call in the application routing using tetra.controller.exec() function.

Browser-side

app.exec([string] actionName, [string] ctrlName (optional), [object] data, [function] callback)

  • actionName: the name of the action to execute. If there's no action associated, this is the template name with "tmpl_actionName" is the id of the template in the DOM. You could also directly pass the html markup of the template in this variable.
  • ctrlName (optional): the name of the controller where the action is implemented. Optional if there's no action associated.
  • data: data used to evaluate the template.
  • callback: the callback function of the template evaluation. It takes in parameter the generated html and can pass it to a view to insert it in the source.
app.exec('article', 'feed', data, function(html) {  
   _('body').append(html);  
});

Server-side (Node.js)

tetra.controller.exec([string] actionName, [string] ctrlName, [object] req, [object] res, [string] scope)

  • actionName: the name of the action to execute.
  • ctrlName: the name of the controller where the action is implemented.
  • req: req object provided by Express Node.js.
  • res: res object provided by Express Node.js.
  • scope: the scope of the controller. This parameter must be set to "node" in a Node.js context.
core.controller.exec(req.params.page, req.params.rep, res, req, 'node');

The response is automatically return by Tetra.js to the client with res.send.

Action logic

You can add some "pre-process" logic to your template by adding an action in the controller. This action take place in a new section actions in the controller constructor.

constr : function(me, app, page, orm) { return {  
   events : {...},  
   actions : {...}, // new "actions" section  
   methods : {...}  
};}

Each action take 2 arguments:

actions : {  
   'article' : function(data, render){  
      var tmplData = {};  
      ...  
      // your logic here  
      ...  
      render(tmplData);  
   },  
   'comments' : function(data, render){...}  
}
  • data [object]: data passed by the app.exec() or the {%-component()%} functions.
  • render [function]: this function call the template evaluation with 2 parameters :
    • tmplData [object]: data used to evaluate the template.
    • name [string]: the template name. This string must be formatted as it: "ctrlName/actionName". By default it takes the controller name and the action name of the current context. This variable also support a single "actionName" or html markup.