Docs

Everything You Need to Know

Templates

Use

ChocolateChip-UI's views use templates to render data. Template are of three types: script/template, markup and string. We really prefer our templates directly where they will be rendered since it shows intent clearly. You could also define a template as a string. This is very tedious if the template is complex. Using a script/template tag or DOM elements is much easier. Besides, when you define a view, it grabs the element's template and caches it for reuse. There is one exception to this, using ES6 template literals. Defining a view's template with a template literal is actually very convenient. The template literal makes it wasy to see what the template is doing, and it's right in the view initialization code.

It's important to note that you can also define templates directly in your views. This has the advantage that the view holds in one place all the information affecting what the view does: template, data/model, and events.

Templates have two important types of markers or delimiters: interpolators and executors. An interpolator tells ChocolateChip-UI to render a data variable. And executor tells ChocolateChip-UI to run a piece of JavaScript. A template can also hold a number sequencer or a template helper.

Script templates are convenient because they hide their content from the browser. ChocolateChip-UI expects script templates to have the type type="text/x-template". Let's put together a template based on an object we want to render.

var myObject = {
  name: {
    first: 'John',
    last: 'Doe'
  },
  age: 32,
  job: 'web developer'
}

// To render this object, 
// we can use the following template:

<template>
  <li>
    <h3>Name: {= data.name.first } {= data.name.last }</h3>
    <h4>Job: {= data.job }</h4>
  </li>
</template>

In the above example, {= } is used to demark a data variable for interpolation by the template renderer. Similary, we can use {{ }} to define blocks of JavaScript to be executed in a template. You might want to do that to conditionally output something.

<template>
  {{ if (somebody.friends && somebody.friends.length) { }}
    {{  somebody.friends.forEach(function(friend) {  }}
    <li> {= friend.name }: {= friend.job }</li>
    {{  });  }}
  {{ } }}
</template>

Sequential Numbering

ChocolateChip-UI provides a way to enable you to output sequential numbering with each repetition of a template. To do so you put $.view.index at the place where you want the number output. By default number starts at 1. But you can tell the view at what number you want it to start. For example, if you wanted it to start at a negative number, just provide that as the argument. The numbering will begin with the negative number provided and increase by 1. Below are some examples:

<template>
  <li>
    <h3>{= $.view.index }: Name: {= data.name.first } {= data.name.last }</h3>
  </li>
</template>

The above example will begin from 1. However, we can tell the view to start at any number. We can do that at setup:

// Tell the view to start from 10:
var PeopleView = new View({
  element: '#peopleList',
  model: PeopleModel,
  startIndexFrom: 10
});
// Or tell the view to start from a negative number:
var PeopleView = new View({
  element: '#peopleList',
  model: PeopleModel,
  startIndexFrom: -20
});

Even after a view is define and rendered, you can change the start index value by running the startIndexFrom method on the view. This cause the view to immediately rerender with the new index value:

PeopleView.startIndexFrom(28);

Formatting Data

ChocolateChip-UI provides several data fromatters that you can use in your templates to control the output of data.

  • formatNumber
  • sum
  • currency
  • formatTime
  • sortDate
  • sortNumbers
  • sortNumbersDescending

You use them as a function with the data you want formatted as the argument. Notice that we are using double quote marks for the arguments in the currency formatter. This is required. Single quotes will throw an exception.:

<template>
  <li>
    <h3>Ammount: {= $.formatNumber(data.number) }</h3>
    <h4>Price: $.currency(data.price, "$", ",", 0)</h4>
  </li>
</template>

You can learn more about data formatters in the documentation.

Template Helpers

You can define your own template helpers to operate on data before it is output by the template. To do that you use the $.defineHelper method:

$.defineHelper({
  bigName: function(data) {
    return data.lastName.toUpperCase();
  }
});  
          

You can then use it like so:

<ul class="list cloak" id="basicRepeater">
  <li>{= $.helpers.bigName(data) }</li>
</ul>
          

When implementing helpers, if you need to quote anything inside the function, make sure you use double quotes with it inside the template. When templates are parsed, all single quotes get escaped. This is so you can have single quotes in English contractions, etc. Unfortunately, with will result in single quotes in JavaScript escaped as well, which will through an exception. So only use double quotes with JavaScript inside a template.

Nested Data Iteration

Data is complicated. Sometimes a property might have an array as its value. and you need to be able to output that in your template. To do this you can write a JavaScript loop in the template to handle the array. Below is some complicated data, followed by a template to render it:

var people = [
  {
    "name": "Wobba",
    "image": "images/Wobba.jpg",
    "friends": [
      {
        "name": "Brennan", 
        "job": "Installer"
      },
      {
        "name": "Josh", 
        "job": "Developer"
      },
      {
        "name": "Pete", 
        "job": "Grand Poobah"
      }
    ]
  },
  {
    "name": "Bozo",
    "image": "images/Bozo.jpg",
    "friends": [
      {
        "name": "Dingo", 
        "job": "Mad Scientist"
      },
      {
        "name": "Bingo", 
        "job": "Gambler"
      },
      {
        "name": "Bango", 
        "job": "Whatever"
      }
    ]
  },
  {
    "name": "Dingo",
    "image": "images/Dingo.jpg",
    "friends": []
  },
  {
    "name": "Apple",
    "image": "images/apple.png",
    "friends": [
      {
        "name": "orange",
        "job": "juice"
      },
      {
        "name": "banana",
        "job": "eating"
      }
    ]
  }
];
<ul class='list' id="complexTemplate">
  <template id='tempie'>
    <li>
      <img data-src='{= somebody.image }'>
      <div>
        <h3>{= somebody.name }</h3>
      </div>
    </li>
    {{ if (somebody.friends && somebody.friends.length) { }}
    <li>
      <div class='no-flex' style='max-width: 100px;'>
        <h3>Friends:</h3>
      </div>
      <div>
        <ol>
          {{  somebody.friends.forEach(function(friend) {  }}
          <li> {= friend.name }: {= friend.job }</li>
          {{  });  }}
        </ol>
      </div>
    </li>
    {{ } }}
  </template>
</ul>

Templates in Views

Although in all the above examples we have been using templates in markup, we can also define templates directly in our views. This has the advantage of having all the information regarding the rendering and behavior of a view in one place. To define a template in a view, you assign it to the view's template property. When doing so, you will need to put a backslash after each new line. Failing to do so will cause a fatal EOF error.

// Define view with string template:
var SimpleView = new View({
  element: '#employees',
  variable: 'employee',
  template: 
  '<li>\
    <div>\
      <h3>{= employee.firstName } {= employee.lastName }</h3>\
      <h4>{= employee.job }</h4>\
      <p>{= employee.performance }<p>\
    </div>\
  </li>'
});
// Render view:
SimpleView.render(fruits);
          

ES6 Template Literals

If you are targetting ES6 or using ES6 and transpiling to ES5 with Babel, Traceur or TypeScript, you can use ES6 template literals to define your templates. This eliminates the need for escaping line endings, etc. You just enclose you template in back ticks. To learn more about using ES6 templates in your app, read about how to set up your app using ES6 with Babel, JSPM, as well as the directions on creating a new project with chui. Below is an example of a template literal:

// Define view with template literal:
var SimpleView = new View({
  element: '#employees',
  variable: 'employee',
  template: 
  `<li>
    <div>
      <h3>{= employee.firstName } {= employee.lastName }</h3>
      <h4>{= employee.job }</h4>
      <p>{= employee.performance }<p>
    </div>
  </li>`
});
// Render view:
SimpleView.render(fruits);
          

Regardless of which approach you take to implementing templates, when ChocolateChipJS parses the template, it converts the template into JavaScript. In the end, the template will be a JavaScript function that evaluates the template values, evaluates any inline JavaScript and returns the markup as DOM nodes.

Escaping Markup or Not

By default ChocolateChip-UI escapes any markup in the data that it renders in a template. This helps prevent the possibility of a malicious script insertion. This also means that tags for bold and italic will come through escaped as well. Possible tags are: <strong>, <em>, <b>, <i>. If you want to be able to render a view that uses data with such tags, you can use the safeHTML flag in your view. Set it to true:

var myView = $.View({
  element: '#myList', 
  safeHTML: true
});

Please be aware that using this attribute on your views does increase the vulnerability of your app. You never know when a malicious hacker will compromise a data source. It's best to scrub your data of any markup and use your templates for defining any formating you need.