Read to use Templates

ChocolateChip-UI provides its own template module. Templates are essential for efficiently creating markup in your app with dynamic content. There are many template engines out there. They are not all equal. In fact, some of the more famous and popular ones are down right slow. ChocolateChip-UI is not the fastest, but it’s faster than most. And it’s small and part of the framework. However, if you prefer a different template engine, you may certainly use it. This is just an option, not mandatory.

There are several ways you can create a template. You can define it as a string assigned to a variable. You can assign it to the $.templates object. You can define it inside a script tag. You could even store your templates as an external file that you import as a script tag, or though an Ajax request. Do what makes sense for you.

Creating and rendering a template is a three stage process. First you write the template. Then you must parse it. This turns the string template into a function that can output markup matched up with data passed to it. And finally you execute that parsed template function with data and output the result to the page:

// This assumes that masterData is an array
// of people's first and last names.

// Define the template:
var masterTemplate = 
'<li>[[= data.firstName ]] [[= data.lastName ]]</li>';
// Prase the template:
var myTmpl8 = $.template(masterTemplate);
// Loop through the data and output the template:
masterData.forEach(function(ctx) {
  // Pass the current chunk of data
  // and output the result to the document:
  $('.master ul').append(myTmpl8(ctx));
});

ChocolateChip uses paris of square brackets as delimiters: [[ ... ]]. These allow you to include executable JavaScript in your templates. The following template would do nothing but launch an alert when the variable name is present:

var template1 = '[[ if (data.name) { ]]\
[[ alert('You have a name!) ]]\
[[ } ]]';

To output a variable into your template’s markup you use an equals sign after the opening square brackets pair: [[= ... ]].

Creating Templates

The most straightforward way to create a template is to define it as a string. If the template will be more than one line, you will need to put a back space on each line, except for the last. Because of the way the parsing is done, to refer to a data variable in the template, you need to use a name as the base. The default is data. You can use any other name that makes sense for the data you are using and pass that name to the parse function as the last parameter.

// Expected data: { "firstName" : "Joe", "lastName" : "Bodoni"}
// Define a template and assign it to the variable 'myTemplate':
var myTemplate = '<li><h3>[[= data.lastName ]], [[= data.firstName ]]</h3></li>';

var parsedTemplate = $.template(myTemplate);

You could also just assign it to ChocolateChip’s $.template object and access it from there:

$.template.myTemplate = '<li><h3>[[= data.lastName ]], [[=data.firstName ]]</h3></li>';

var parsedTemplate = $.template($.templates.myTemplate);

You could also use the $.template object as a cache for you parsed templates. You would do this during load time. The advantage is that they are globally available and ready to use at any time:

// Define the temlpate:
var myTemplate = '<li><h3>[[= data.lastName ]], [[= data.firstName ]]</h3></li>';
// Parse it and cache it in $.templates:
$.templates.parseTempate = $.template(myTemplate);

Custom Data Names

When parsing a template, you can also define a custom name for the data in your template. You would also need to use that custom name in your template or it will generate and error:

// Use 'user' instead of 'data':
var myTemplate = '<li><h3>[[= user.lastName ]], [[= user.firstName ]]</h3></li>';
// Provide 'user' as custom name when parsing:
var parsedTemplate = $.template(myTemplate, 'user');

Presuming we had a JSON object for students like this, we can easily put together a template to output it:

var studentObj = {
   "students": [
      { 
         "firstName":"Joe",
         "lastName": "Bodoni",
         "major":"Physics" 
       }, 
       { 
         "firstName":"Suzy",
         "lastName": "Que",
         "major":"Chemistry" }, 
       { 
         "firstName":"John",
         "lastName": "Doe",
         "major":"Mathematics" 
       }
   ],
   "university" : "Palo Alto",
   "year": "1950"
}

// 'student' will represent each iteration of the "Students" array above:
var studentsTpl = '<li><h3>[[= student.lastName]], [[= student.firstName ]]</ h3><h4>[[= student.major ]]</h4></li>';
var parsedStudentTmp = $.template(studentsTpl, 'student');

var list = $('#studentList');
// Iterated over the Students array:
studentObj.students.forEach(function(ctx) {
   // Append template with data:
   list.append(parsedStudentTmp(ctx));
});

Using a Script Tag as a template

As mentioned earlier, you can store you template in a script tag. To get the template, you use a selector to get the tag and then grab its text content as the template. Remember to give the tag a custom type. This will prevent the browser from showing the contents of the script tag in the document. Browsers ignore the contents of script tags with an unknown type. We recommend using ‘text/x-template’, but you can use whatever you want, as long as it is not a know type. In the example below we gave the script and id so we can easily get it.

<script id='studentTemplate' type='text/x-template'>
   <li><h3>[[= student.lastName]], [[= student.firstName ]]</h3><h4>[[= student.major ]]</h4></li>
</script>   

var studentTemplate = $('#studentTemplate').text();
var parsedStudents = $.template(studentTemplate, 'student');
var list = $('#studentList');
// Iterated over the Students array:
studentObj.students.forEach(function(ctx) {
    // Append template with data:
    list.append(parsedStudentTmp(ctx));
});

JavaScript in Templates

ChocolateChip allows you to execute JavaScript code inside your template while it is being rendered. You could use this for some type of boolean check:

// Supposing the following data structure: songs = [ { title: ‘whatever’, artist: ‘whoever’, album: ‘something’, description: ‘blah blah’, genre: ‘pop’ }, etc. ];

var songs = "<li>\
[[ if (song.genre === 'pop') { ]]\
   <li>\
      <h3>[[= song.title ]]</h3>\
      <h4>[[= song.artist ]]</h4>\
      <p>[[= song.detail ]]</h4>\
   </li>\
[[ } else { ]]\
   <li>\
      <h3>No Match</h3>\
   </li>\
[[ } ]]";

Or, as a script template:

<script id='songTemplate' type='text'/x-template'>
   <li>
   [[ if (song.genre === 'pop') { ]]
      <li>
         <h3>[[= song.title ]]</h3>
         <h4>[[= song.artist ]]</h4>
         <p>[[= song.detail ]]</h4>
      </li>
   [[ } else { ]]
      <li>
         <h3>No Match</h3>\
      </li>
   [[ } ]]
</script>

Example

You can try out this live example of templates on Codepen.

$.template.repeater

This method enables you to output a template repeatedly based on the value of an array of data. This method can take two types of arrays: simple or consisting of objects. Using other data types will throw and error. You could use either of the following types of arrays:

var simpleArray = ["one", "two", "three", "four", "five"];
var arrayOfObjects = [
  {firstName: "John, lastName: "Doe", age: 22},
  {firstName: "Suzy", lastName: "Que", age: 21},
  {firstName: "Joe", lastName: "Bodoni", age: 30}
];

$.template.repeater takes three arguments:

  • element: the target in which the result will go
  • template: the template to repeat
  • data: an array of repeatable data

Below are two examples of how to use $.template.repeater:

<body>
  <ol id='arrayList'>
  </ol>
  <ul id="objectArrayList"></ul>
</body>


/* The JavaScript: */
$(function() {
  // Output a simple array of data:
  var simpleArray = ['One','Two', 'Three', 'Four', 'Five'];
  var repeaterTmplate1 = '<li>[[= data ]]</li>';
  $.template.repeater($('#arrayList'), repeaterTmplate1, simpleArray);

  // Output an array of objects:
  var arrayOfObjects = [
    {firstName: "Albert", lastName: "Einstein"},
    {firstName: "Steven", lastName: "Hawking"},
    {firstName: "Neil", lastName: "deGrasse Tyson"}
  ];
  var repeaterTmplate2 = '<li>[[= data.firstName ]], [[= data.lastName]]</li>';
  $.template.repeater($('#objectArrayList'), repeaterTmplate2, arrayOfObjects);
});

This will produce the following:

<ol id="arrayList">
  <li>One</li>
  <li>Two</li>
  <li>Three</li>
  <li>Four</li>
  <li>Five</li>
</ol>
<ul id="objectArrayList">
  <li>Albert, Einstein</li>
  <li>Steven, Hawking</li>
  <li>Neil, deGrasse Tyson</li>
</ul>

Behavior: By default, $.template.repeater appends its results to the target element. If you want it to replace the contents, then simple use $(selector).empty() before executing $.template.repeater()

Declarative Template Repeater

ChocolateChip-UI also provides a way to use declarative repeater templates. You do this by putting the attribute data-repeat with its value being the name of a variable of the array of data you want it to render with. Because of the way JavaScript scopes work, you need to expose the data to the template engine so that it can parse the template with it. You do this by assigning it to $.template.data:

// Define some data:
var renaissanceLuminaries = { persons: 
  [
    {firstName: "Albert", lastName: "Einstein"},
    {firstName: "Steven", lastName: "Hawking"},
    {firstName: "Neil", lastName: "deGrasse Tyson"},
    {firstName: "Leonardo", lastName: "Da Vinci"},
    {firstName: "Nicholas", lastName: "Copernicus"}  
  ]
};
// Expose the data to the $.template.data object:
$.template.data['luminaries'] = renaissanceLuminaries.persons;

Don’t worry about this duplicating your data and taking up memory. After the template gets rendered, ChocolateChip-UI will delete the data object so that its memory gets garbage collected.

Setting up a declarative template repeater is simple:

<ul id="repeater" data-repeater="luminaries" class='cloak'>
  <li>[[= data.firstName ]], [[= data.lastName]]</li>
</ul>

With the template defined and our data assigned to the $.template.data object, we can invoke the repeater method. We do without passing any parameters. Every time you do so, it will search your document for declarative repeaters, so be careful to only do it when all templates have their data ready for render, because after rendering, that data gets deleted from the template data object.

// Parse any declarative repeaters:
$.template.repeater();

Note: You can keep the unrendered template of the declarative repeater from showing by putting the class “cloak” on it. You can see that class on the repeat above. This class hides the child elements of the repeater. When ChocolateChip-UI renders the repeater, it takes this class off before injecting the repetitive content into it.

$.template.index

When using a repeater, you may need to know what iteration your own, say, to output a numberic value. ChocolateChip-UI templates provides a way for you to do this using $.template.index. Like other JavaScript loop processes, it starts with 0 and increases after that. So, if you want to output numbers, you’ll need to increase them by 1. Here’s an example:

<ul id="repeater" data-repeater="luminaries" class='cloak'>
  <li>[[= $.template.index + 1 ]]: [[= data.firstName ]], [[= data.lastName]]</li>
</ul>

This would create the following markup:

<ul id="luminaries">
  <li>1: Albert, Einstein</li>
  <li>2: Steven, Hawking</li>
  <li>3: Neil, deGrasse Tyson</li>
</ul>

Images

If you want to have images in a declarative repeater, you need to use a special attribute for the source. At load time the browser will see the declarative template in the markup and try to parse the image’s source. If the path of the image is based on dynamic data, this will result in an error being logged in the browser’s console. You can avoid this by using data-src instead of src:

<ul id="repeater" data-repeater="luminaries" class='cloak'>
  <li>
     <img data-src="[[= data.image ]]"> 
     <span>[[= data.firstName ]], [[= data.lastName]]</span>
  </li>
</ul>

At parse time, ChocolateChip-UI will convert the data-src attribute into a src attribute.

Note: One last thing to bear in mind. Because template variables are actually JavaScript variables, you can perform any appropriate JavaScript operations directly on them. We are already doing that by increase the value of the $.template.index by 1 in each loop in the template above. Or you might want to do something such as capitalizing the last name using String.toUpperCase():

<ul id="repeater" data-repeater="luminaries" class='cloak'>
  <li>[[= $.template.index + 1 ]]: [[= data.firstName ]], [[= data.lastName.toUpperCase() ]]</li>
</ul>

About the Author Adam

Leave a Comment: