While writing templates we often have the task of displaying common visual elements, such as alerts, dialogs, and lists. These elements may have a complex internal structure, and writing a template every time to map the model to this structure can be an error-prone and repetitive process.
Handlebars allows us to simplify the writing of templates containing common elements by replacing the template for the common element with a call to helpers.
In this recipe, we're going to write Handlebars helpers to render links, images, and unordered lists. We're going to display a list of people with their name, photo, and link to their profile.
We need to download Handlebars from https://github.com/wycats/handlebars.js. The browser version is in the dist
directory. Create a directory for the example and copy handlebars.js
to this directory, or download directly (on Linux):
wget https://raw.github.com/wycats/handlebars.js/master/dist/handlebars.js
Follow these steps:
index.html
, which will contain the list style, list placeholder, and list template. The template will utilize our new helpers:<!DOCTYPE HTML> <html> <head> <title>Helpers in Handlebars</title> <style type="text/css"> li { padding:1em; } li img { vertical-align:middle; } </style> </head> <body> <div id="list"> </div> <script id="template" type="text/x-handlebars-template"> {{#ul list}} {{img image alt=name}} {{name}} {{else}} No items found {{/ul}} </script> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script> <script type="text/javascript" src="handlebars.js"></script> <script type="text/javascript" src="example.js"></script> </body> </html>
example.js
:$(function() { Handlebars.registerHelper('ul', function(items, options) { if (items .length) return '<ul>' + items.map(function(item) { return '<li>' + options.fn(item) + '</li>'; }).join('') + '</ul>' else return options.inverse(this); }); Handlebars.registerHelper('img', function(src, options) { return new Handlebars.SafeString('<img src="' + src + '" alt="'+ (options.hash['alt'] || '') + '" title="'+ (options.hash['title'] || '') + '">'), }); var template = Handlebars.compile($('#template').html()); $('#list').html(template({list:[ { name: 'John', image: '1.png'}, { name: 'Jack', image: '2.jpg'}, { name: 'Jenny', image: '3.jpg'}, ]})); });
Inside our template, we're using two new helpers, ul
to display lists and the img
tag to display images.
Handlebars has two different types of helpers: regular and block. Block helpers are invoked in the following format:
{{#helperName argument param=value otherparam=value}} body {{else}} alternative {{/name}}
When Handlebars encounters a block, it invokes its block function, which takes one or two arguments:
function helper(argument, options) { … }
If specified, the first argument is passed to the helper
function. If the first argument is not available, the options
argument becomes first.
The named parameters are also optional, and are available inside the options
argument in the hash
property that is, options.hash
.
Next comes the mandatory block argument, available inside the helper
function as options.fn
. The block argument is a function that takes a context and returns the result of rendering the block with that context
The else
block is also a block function (options.inverse
). It is optional and can be omitted. If omitted, a default empty block function is passed as options.inverse
instead.
In our example we pass the list contents to our ul
helper. This helper uses the regular block on each item if there are items in the list; otherwise it uses the alternative block to display the empty list message.
The other type of helper is a regular helper and can be invoked as follows:
{{helperName argument param=value otherparam=value}}
Normal helpers work similarly, to the block helpers, except that they don't receive the block parameters. In our example, we pass the alt
text to the rendered image as a named parameter.
Both types of helpers should return the rendered HTML.
In our example.js
file, we register our two new helpers by calling Handlebars.registerHelper
. This makes them available to all subsequent templates that we need to render. Afterwards, we can call render
on the template with our data, which in turn invokes the helpers to generate the resulting HTML:
<ul> <li> <img src="1.png" alt="John" title=""> John </li> <li> <img src="2.jpg" alt="Jack" title=""> Jack </li> <li> <img src="3.jpg" alt="Jenny" title=""> Jenny </li> </ul>
18.216.117.191