Write Templates Like A Node.js Pro: Handlebars Tutorial

Write Templates Like A Node.js Pro: Handlebars Tutorial

I’ve wrote how I struggled with Jade, but I had no choice except to master it. However, before beginning to understand Jade, I admired Handlebars GREATLY. I did it mostly for its simplicity and similarity with plain HTML.

If you want to write templates for Node.js apps, then consider Handlebars. This short tutorial will get you started on the path of becoming a pro. And if you haven’t even heard about Handlebars, then you’re missing out big time!

Here’s the outline of this post:

  • Handlebars syntax
  • Handlebars standalone usage

Handlebars Syntax

The Handlebars library is another template engine. It inherits from Mustache and, for the most part, is compatible with Mustache’s syntax. However, Handlebars adds more features (i.e., a superset).

Unlike Jade, by design, Handlebars was made so that developers can’t write a lot of JavaScript logic inside the templates. This helps to keep templates lean and related strictly to the representation of the data (no business logic).

Another drastic difference between Jade and Handlebars is that the latter requires full HTML code (<,>, and soon), and for this reason it could care less about whitespace and indentation.

Variables

A Handlebars expression is {{, some content, followed by }}, hence the name of the library (see the resemblance to handlebars on a bicycle?). For example, the Handlebars code:

<h1>{{title}}</h1>
<p>{{body}}</p>

with data:

{
  title: "Express.js Guide",
  body: "The Comprehensive Book on Express.js"
}

renders:

<h1>Express.js Guide</h1>
<p>The Comprehensive Book on Express.js</p>

Iteration (each)

In Handlebars, each is one of the built-in helpers; it allows you to iterate through objects and arrays. Inside the block, we can use @key for the former (objects), and @index for the later (arrays). In addition, each item is referred to as this. When an item is an object itself, this can be omitted and just the property name is used to reference the value of that property.

The following are examples of the each helper block in Handlebars:

<div>
{{#each languages}}
  <p>{{@index}}. {{this}}</p>
{{/each}}
</div>

The template above is supplied with this data:

{languages: ['php', 'node', 'ruby']}

And output this HTML upon compilation:

<div>
  <p>0. php</p>
  <p>1. node</p>
  <p>2. ruby</p>
</div>

Unescaped Output

By default, Handlebars escapes values. If you don’t want Handlebars to escape a value, use triple curly braces: {{{ and }}}.

As data, let’s use this object that has an array with some HTML tags (angle braces):

{
  arr: [
    '<a>a</a>',
    '<i>italic</i>',
    '<strong>bold</strong>'
  ]
}

To apply this Handlebars template to our data above (i.e., hydration):

<ul>
   {{#each arr}}
    <li>
      <span>{{@index}}</span>
      <span>unescaped: {{{this}}} vs. </span>
      <span>escaped: {{this}}</span>
    </li>
  {{/each}}
</ul>

The hydrated template produces this HTML:

<ul>
  <li>
    <span>0</span>
    <span>unescaped: <a>a</a> vs. </span>
    <span>escaped: &lt;a&gt;a&lt;/a&gt;</span>
  </li>
  <li>
    <span>1</span>
    <span>unescaped: <i>italic</i> vs. </span>
    <span>escaped: &lt;i&gt;italic&lt;/i&gt;</span>
  </li>
  <li>
    <span>2</span>
    <span>unescaped: <strong>bold</strong> vs. </span>
    <span>escaped: &lt;strong&gt;bold&lt;/strong&gt;</span>
  </li>
</ul>

Conditions (if )

if is another built-in helper invoked via #. For example, this Handlebars code:

{{#if user.admin}}
  <button class="launch">Launch Spacecraft</button>
{{else}}
   <button class="login"> Log in</button>
{{/if}}

populated with data:

{
  user: {
    admin: true
  }
}

turns into this HTML output:

<button class="launch">Launch Spacecraft</button>

Unless

To inverse an if not ... (if ! ...)statement (convert negative to positive), we can harness the unless built-in helper block. For example, the previous code snippet can be rewritten with unless.

The Handlebars code that check the truthness of the admin flag (property user.admin):

{{#unless user.admin}}
   <button class="login"> Log in</button>
{{else}}
  <button class="launch">Launch Spacecraft</button>
{{/unless}}

We supply our template with this data that means that the user is the administrator:

{
  user: {
    admin: true
  }
}

The HTML output renders the launch button, which is available only to admins:

<button class="launch">Launch Spacecraft</button>

With

In case there’s an object with nested properties, and there are a lot of them, it’s possible to use with to pass the context.

We have this Handlebars code that is handling a user’s contact and address information:

{{#with user}}
<p>{{name}}</p>
{{#with contact}}
<span>Twitter: @{{twitter}}</span>
{{/with}}
<span>Address: {{address.city}},
{{/with}}
{{user.address.state}}</span>

Then we merge the template with this data. Notice the properties’ names are the same as in the Handlebar template, there’s only one reference to the user object:

{user: {
  contact: {
    email: 'hi@azat.co',
    twitter: 'azat_co'
  },
  address: {
    city: 'San Francisco',
    state: 'California'
  },
  name: 'Azat'
}}

The snippets above when compiled, produce HTML:

<p>Azat</p>
<span>Twitter: @azat_co</span>
<span>Address: San Francisco, California
</span>

Comments

To output comments, use regular HTML <!-- and -->. To hide comments in the final output, use {{! and }} or {{!-- and --}}. For example:

<!-- content goes here -->
<p>Node.js is a non-blocking I/O for scalable apps.</p>
{{! @todo change this to a class}}
{{!-- add the example on {{#if}} --}}
<p id="footer">Copyright 2014 Azat</p>

outputs:

<!-- content goes here -->
<p>Node.js is a non-blocking I/O for scalable apps.</p>
<p id="footer">Copyright 2014 Azat</p>

Custom Helpers

Custom Handlebars helpers are similar to built-in helper blocks and Jade mixins. To use custom helpers, we need to create them as a JavaScript function and register them with the Handlebars instance.

This Handlebars template uses our custom helper table which we’ll register (i.e., define) later in the JavaScript/Node.js code:

{{table node}}

Here goes the JavaScript/Node.js that tells the Handlebars compiler what to do when it encounters the custom table function (i.e., print an HTML table out of the provided array):

Handlebars.registerHelper('table', function(data) {
  var str = '<table>';
  for (var i = 0; i < data.length; i++ ) {
    str += '<tr>';
    for (var key in data[i]) {
      str += '<td>' + data[i][key] + '</td>';
    };
    str += '</tr>';
  };
  str += '</table>';

  return new Handlebars.SafeString (str);
});

This is our table data:

{
  node:[
    {name: 'express', url: 'http://expressjs.com/'},
    {name: 'hapi', url: 'http://spumko.github.io/'},
    {name: 'compound', url: 'http://compoundjs.com/'},
    {name: 'derby', url: 'http://derbyjs.com/'}
   ]
}

The resulting HTML output looks like this:

<table>
    <tr>
        <td>express</td>
        <td>http://expressjs.com/
    </td>
    </tr>
        <tr><td>hapi</td>
    <td>http://spumko.github.io/
    </td>
    </tr>
    <tr>
        <td>compound</td>
        <td>http://compoundjs.com/
    </td>
    </tr>
    <tr>
        <td>derby</td>
        <td>http://derbyjs.com/</td>
    </tr>
</table>

Includes (Partials)

Includes or partials templates in Handlebars are interpreted by the {{>partial_name}} expression. Partials are akin to helpers and are registered with Handlebars.registerPartial(name, source), where name is a string and source is a Handlebars template code for the partial.

Standalone Handlebars Usage

Developers can install Handlebars via NPM with $ npm install handlebars or $ npm install handlebars –save, assuming there’s either node_modules or package.json in the current working directory (see the results of a sample installation in Figure 4–3).

Figure 4–3. Installing Handlebars
Figure 4–3. Installing Handlebars

■Note Handlebars can be installed via NPM as a command-line tool with the -g or --global options. For more information on how to use Handlebars in this mode, refer to the $ handlebar command or the official documentation(https://github.com/wycats/handlebars.js/#usage–1).

Here’s an example of standalone Node.js Handlebars usage from handlebars-example.js:

var handlebars = require('handlebars'),
  fs = require('fs');

var data = {
  title: 'practical node.js',
  author: '@azat_co',
  tags: ['express', 'node', 'javascript']
}
data.body = process.argv[2];

fs.readFile('handlebars-example.html', 'utf-8', function(error, source){
  handlebars.registerHelper('custom_title', function(title){
    var words = title.split(' ');
    for (var i = 0; i < words.length; i++) {
      if (words[i].length > 4) {
        words[i] = words[i][0].toUpperCase() + words[i].substr(1);
      }
    }
    title = words.join(' ');
    return title;
  })

  var template = handlebars.compile(source);
  var html = template(data);
  console.log(html)
});

And the handlebars-example.html file that uses custom_title helper has this content that calls the helper and outputs some other properties:

<div class="header">
    <h1>{{custom_title title}}</h1>
</div>
<div class="body">
    <p>{{body}}</p>
</div>
<div class="footer">
    <div><a href="http://twitter.com/{{author.twitter}}">{{autor.name}}</a>
    </div>
    <ul>
      {{#each tags}}
        <li>{{this}}</li>
      {{/each}}
    </ul>
</div>

To produce this HTML when we run $ node handlebars-example.js 'email body', use the following:

<div class="header">
    <h1>Practical Node.js</h1>
</div>
<div class="body">
    <p>email body</p>
</div>
<div class="footer">
    <div><a href="http://twitter.com/"></a>
    </div>
    <ul>
        <li>express</li>
        <li>node</li>
        <li>javascript</li>
    </ul>
</div>

To use Handlebars in the browser, download the library in a straightforward manner from the official web site(http://handlebarsjs.com/) and include it in your pages. Alternatively, it’s possible to use just the runtime version from the same web site (which is lighter in size) with precom piled templates. Templates can be precompiled with the Handlebars command-line tool.

 

This wraps up the quick Handlebars tutorial.

In the next post, I’ll show how to use Jade and Handlebars in Express.js.

Author: Azat

Techies, entrepreneur, 20+ years in tech/IT/software/web development expert: NodeJS, JavaScript, MongoDB, Ruby on Rails, PHP, SQL, HTML, CSS. 500 Startups (batch Fall 2011) alumnus. http://azat.co http://github.com/azat-co

9 thoughts on “Write Templates Like A Node.js Pro: Handlebars Tutorial”

  1. Good article! But I’m still not sure if the errors in the code (‘autor’ instead of ‘author’, and some missing properties in the data like ‘author.name’ and ‘author.twitter’ ) are intentional on not :-)
    Thanks anyway!

  2. I like using express3-handlebars . While Jade has it’s benefits, I don’t like ditching HTML completely. Anyhow, very informative tutorial.

  3. Thank you for a good article, it helped me so much)
    Other authors usually explain handlebars on servers, based on Express. In my case, i don’t want to use Express.

  4. You like everyone else trying to explain Handelbars just basically copy and paste. For example when using Helpers. Where did you get the “Handlebars.” from?

  5. A Handlebars expression is {{, some content, followed by }}, hence the name of the library (see the resemblance to handlebars on a bicycle?)

    handlebars is a type of Mustache ;)

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.