Template

Mev-Rael edited this page Feb 5, 2016 · 4 revisions
  1. Basic usage
  2. Passing data to templates
  3. Template as a table row and multiple insert
  4. Tree view and adjacency list
  5. Template handlers
  6. Template events, data parsing/escaping and transformation

Basic usage

Template base object used for adding sections of HTML to document and attaching variables and handlers to it.

Template contents should be inside any block element with id = "template_..." (template wrapper). For example:

<div id="template_user_block">
  <div class="app-block-user">
    <div class="app-block-user-header"></div>
    <div class="app=block-user-body">
      <img src="" alt="Profile photo" class="app-block-user-img">
      <p class="app-block-user-about"></p>
    </div>
  </div>
</div>

Templates first should be defined with Template.define(template_id). When template is defined contents of wrapper are removed and placed into document fragment so there is no need of hiding templates.

It is recommended to add all templates at the bottom of the page.

Templates can be inserted into document with Template.insert(template_id, data = {}, parent_el). Second argument data can be omitted by passing empty object {} or empty array [] but not any other value. Third argument parent_el should be a valid document node. Example:

import { Template } from 'bunnyjs/src/bunny.template';

Template.define('template_user_block');

document.addEventListener('DOMContentLoaded', function(e) {
  Template.insert('template_user_block', [], document.querySelector('.container'));
}, false);

Passing data to templates

Data in templates can be placed in tag contents (innerHTML) or in attribute value.

For tag contents add attribute v="data_key" to this element. v stands for variable. For attribute value add attribute av="attribute_name:data_key". av stands for attribute variable. Example:

<div id="template_user_block">
  <div class="app-block-user">
    <div class="app-block-user-header" v="name"></div>
    <div class="app=block-user-body">
      <img src="" alt="Profile photo" class="app-block-user-img" av="src:photo_path">
      <p class="app-block-user-about" v="about"></p>
    </div>
  </div>
</div>

Now data can be placed into template with:

var data = {
  name: 'John',
  photo_path: '/img/john.png',
  about: 'User description'
};

Template.insert('template_user_block', data, document.querySelector('.container'));

Template as a table row and multiple insert

If template is for table row then template wrapper should be table tag because browsers will remove tr contents if not inside table. Example:

<table id="template_user_row">
  <tr>
    <td v="name"></td>
    <td><img src="" alt="Profile photo" av="src:profile_photo"></td>
    <td v="about"></td>
  </tr>
</table>

To insert same template many times Template.insertAll(template_id, data_collection, parent_el) should be used. It is not recommended to insert templates into DOM one by one. insertAll() method will iterate through data_collection which should be an array of data and create single document fragment and will made only one real DOM manipulation at the end.

var data_collection = [
  {
    name: 'John',
    photo_path: '/img/john.png',
    about: 'User description'
  },
  {
    name: 'Oliver',
    photo_path: '/img/oliver.png',
    about: 'User 2 description'
  }
];

Template.insertAll('template_user_row', data_collection, document.querySelector('.container_table'));

Tree view and adjacency list

For example, you need to put comments, replies and so on in tree view. This is possible with Template.insertAdjacencyList(tpl_id, data_adj_list, parent_el, parent_id_column, branch_container_class, order)

...

Template handlers

Let say you have a button in form and need to attach onClick event on this button when template is inserted into DOM.

This is done by adding data-handler="function_name" to button in template. Data handler function should be defined and passed as a 2nd argument when defining a template with Template.define(tpl_id, handlers = {}) where handlers is an object where keys are function_names and values - callbacks. Callbacks will receive 3 arguments: first will be an element to which data-handler attribute was added. In our case - to button. However, data-handlers can be placed anywhere inside template. Second - escaped_data and third - template_nodes (All root nodes and their child inside template wrapper, usually it's single div or tr). Example:

<div id="template_popup">
  <div class="app-popup">
    <div class="app-popup-body">
      ...
    </div>
    <div class="app-popup-footer">
      <button class="app-btn" data-handler="popup_close">Close</button>
    </div>
  </div>
</div>
Template.define('template_popup', {
  popup_close: function(el, escaped_data, tpl_nodes) {
    el.addEventListener('click', function(e) {
      // remove popup from screen by deleting all inserted nodes
      tpl_nodes.forEach(function(node) {
        node.parentNode.removeChild(node);
      });
    });
  }
});

Template events, data parsing/escaping and transformation

The third and last argument can be passed to Template.define() is object of template events. They can be used for example on template init or to modify data before rendering. To do so use:

Template.define(tpl_id, {}, {
   format_data: function(data) {
     data.name = data_first_name + ' ' + data.last_name;
     data.created_at = // modified data.created_at with custom format, for example.
     return data; // don't fortget to return modified data
   }
});

Each template event name has constant, for example, instead of format_data - TEMPLATE_EVENT_FORMAT_DATA can be used. format_data event is fired BEFORE template is parsing/escaping data.

Template automatically parses data and escapes HTML.

It is recommended to store data as is in database and only parse and escape it before rendering in browser. So Template is saving from XSS and there is no need to worry about it. Template also replaces new lines with br tag. So basicly no work on data is needed on backend.

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.