Handlebars - Basic

handlebars

What is Handlebars?

Handlebars is a front-end JavaScript templating engine which make string concatenation much easier. It’s an extension of Mustache with a few additional features. Mustache is fully logic-less but Handlebars adds minimal logic thanks to the use of some helpers (such as if, with, unless, each and more).

Handlebars.js and Mustache are both logicless templating languages that keep the view and the code separated like we all know they should be.

How close is Handlebars to Mustache?

Handlebars is an extension of Mustache with a few additional features. It is largely compatible with Mustache templates. In most cases it is possible to swap out Mustache with Handlebars and continue using your current templates. Complete details can be found here.

  1. Handlebars.js adds a couple of additional features to make writing templates easier and also changes a tiny detail of how partials work.
    1. Paths and nested paths: Handlebars.js supports an extended expression syntax that we call paths. Paths are made up of typical expressions and . characters. Expressions allow you to not only display data from the current context, but to display data from contexts that are descendants and ancestors of the current context. To display data from descendant contexts, use the . character. You can backtrack using ../. For example, if you've already traversed into the person object you could still display the company's name with an expression like {{../company.name}}
    2. Helpers
    3. Blocks: Blocks are similar to sections in Mustache, but are not exactly the same.
    4. Literal Values
    5. Delimited Comments

There are a few Mustache behaviors that Handlebars does not implement:

  1. Handlebars deviates from Mustache slightly in that it does not perform recursive lookup by default. The compile time compat flag must be set to enable this functionality. Users should note that there is a performance cost for enabling this flag. The exact cost varies by template, but it's recommended that performance sensitive operations should avoid this mode and instead opt for explicit path references.
  2. The optional Mustache-style lambdas are not supported. Instead Handlebars provides its own lambda resolution that follows the behaviors of helpers.
  3. Alternative delimiters are not supported.

How can we download, install and load Handlebars into our application?

  1. Download from the web site: Go to http://handlebarsjs.com/installation.html and click on the appropriate download link
  2. npm (see below)
  3. bower (see below)

npm:

npm install --save handlebars
npm install handlebars -g
require('handlebars');
require('handlebars/runtime'); // or just the runtime

handlebars <input> -f <output>

The browser builds are located in the node_modules/handlebars/dist/ directory. Making these accessible to the browser will depend on what build system you are using but this may be as simple as copying the files to an acessible place. This is the preferred method of installation when using the precompiler as it ensures that your precompiled templates always run against the same version of the runtime.

Using the -g flag installs the package globally, so it can be used in any project.

bower:

bower install --save handlebars

The default bower library is UMD-style so this should work properly with global, CJS, and AMD module systems. handlebars.js and handlebars.runtime.js are the primary source files but a number of other options exist in this component. We recommend looking at them and selecting the best one for your needs. This component should also work with other packagers such as component but these have not been tested as throughly.

How can we use Handlebars?

Handlebars templates look like regular HTML, with embedded handlebars expressions:

<script id="entry-template" type="text/x-handlebars-template">
  <div class="entry">
    <h1>{{title}}</h1>
    <div class="body">
      {{body}}
    </div>
  </div>
</script>

<script type="text/javascript">
    var source   = $("#entry-template").html();
    var template = Handlebars.compile(source);

    var context = {title: "My New Post", body: "This is my first post!"};
    var html = template(context);
</script>

In the above code, we use a script tag to deliver the template to the browser. Notice the type attribute of the first script tag. We then use jQuery to obtain the content of the script tag, which is the content of the template, and we use Handlebars.compile to compile the template. We then evaluate the template, and the result is returned to us as a string which is HTML, and we can do whatever we want with that string.

The context object in the above code is known as the view object in other templating engine. The keys (or tokens), such as title, is used to link the view object together with the template. Like mustache, for each token found in the template, handlebars use the token or its name to look up the data for the token in the view object, and based on the type of the data, handlebars do different thing. If the data for the token is just a simple literal value, handlebars insert the value into the template. If the data for the token is an array, Handlebars will iterate over each item in the array, setting the current context to that item. If the data for the token is a function, handlebars invoke the function. See below for more details.

What is an expression?

An expression is whatever we include inside {{ ... }}

The simplest dynamic element in a Handlebars template is an expression. An expression is surrounded by handlebars, like {{expression}}.

What are the different types of expressions?

  1. normal expression mentioned above
  2. block expression mentioned below

What happen when Handlebars encounter a normal expression?

When an expression is reached in the template, Handlebars will look for an item in the current context that matches the expression given. If the matching item is a value, the value is output. If the matching item is a function, the function is called. If no matching item is found, nothing is written to the output.

What is a block and what is a block expression?

Blocks are represented in Handlebars with the pound (#) symbol. Handlebars' blocks have the same syntax as Mustache's sections, but should not be confused with one another. In the example below, the stuff between {{#person}} and {{/person}} is a block.

var data = { person: {
    firstName: "Alan",
    lastName: "Johnson",
    email: "alan@test.com",
    phone: "123-456-7890"
  } };

<script type="text/x-handlebars-template">
  {{#person}}
    <div>Name: {{firstName}} {{lastName}}</div>
    <div>Email: {{email}}</div>
    <div>Phone: {{phone}}</div>
  {{/person}}
</script>

From one point of view, a block expression is like the normal expression. It is an expression, or a value (a value can be a literal value, an array, an object, or a function). From another point of view, a block expression is synonymous to just a block or a section of the template, but entire thing (everything between {{#person}} and {{/person}}) is still just an expression.

You can think of a block or section as a sub-template that is directly included in a bigger template. When Handlebars / Mustache encounters a block or section, the sub-template for that block (or the compiled code of that sub-template) is executed and the result is inserted into the output stream.

What does Handlebars do when it encounter a block expression if the block expression evaluates to an array?

If the block expression given evaluates to an array, Handlebars will iterate over each item in the Array, setting the current context to that item, and that portion of the template is executed and is inserted into the output stream. Because blocks change the current expression context, Handlebars supports using the ../ expression to access parent contexts.

What does Handlebars do when it encounter a block expression if the block expression evaluates to anything other than an array?

If a block’s expression evaluates to anything other than an array, Handlebars simply sets the context to the result of evaluating the expression. This can save a lot of typing when outputting several properties of an object.

var data = { person: {
    firstName: "Alan",
    lastName: "Johnson",
    email: "alan@test.com",
    phone: "123-456-7890"
  } };

<script type="text/x-handlebars-template">
  {{#person}}
    <div>Name: {{firstName}} {{lastName}}</div>
    <div>Email: {{email}}</div>
    <div>Phone: {{phone}}</div>
  {{/person}}
</script>

The above code demonstrate what happens when Handlebars encounter a block expression and it evaluates to an object. It also shows that Handlebars dynamically change the context for the block to that object instead of using the current context object. This save a lot of typing especially when we need to output a lot of properties of that object.

How are Handlebars' blocks different from Mustache' sections?

Handlebars' blocks have the same syntax as Mustache's sections but should not be confused with one another. Sections are akin to an implicit each or with statement depending on the input data.

With Mustache, the view / context object can contain function, and when Mustache encounters a section, and if that section evaluate to a function, the function get invoked. If the section evaluates to an array, Mustache iterate over the array. I think this is also true with Handlebars. I need to check the documentations for both Mustache and Handlebars on this.

What is a path?

Handlebars.js supports an extended expression syntax that we call paths. Paths are made up of typical expressions and . characters. Expressions allow you to not only display data from the current context, but to display data from contexts that are descendants and ancestors of the current context. To display data from descendant contexts, use the . character.

You can backtrack using ../. For example, if you've already traversed into the person object you could still display the company's name with an expression like {{../company.name}}

Handlebars supports simple paths, just like Mustache.

<p>{{name}}</p>

How does Handlebars support nested path?

Handlebars also supports nested paths, making it possible to look up properties nested below the current context.

<div class="entry">
  <h1>{{title}}</h1>
  <h2>By {{author.name}}</h2>

  <div class="body">
    {{body}}
  </div>
</div>

That template works with this context

var context = {
  title: "My First Blog Post!",
  author: {
    id: 47,
    name: "Yehuda Katz"
  },
  body: "My first post. Wheeeee!"
};

Handlebars supports nested paths by using the dot notation (see the dot inside the {{ }} in the above code).

Nested handlebars paths can also include ../ segments, which evaluate their paths against a parent context.

<h1>Comments</h1>

<div id="comments">
  {{#each comments}}
  <h2><a href="/posts/{{../permalink}}#{{id}}">{{title}}</a></h2>
  <div>{{body}}</div>
  {{/each}}
</div>

Even though the link is printed while in the context of a comment, it can still go back to the main context (the post) to retrieve its permalink.

The ../ path segment references the parent template scope, not one level up in the context. This is because block helpers can invoke a block with any context, so the notion of "one level up" isn't particularly meaningful except as a reference to the parent template scope.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License