Handlebars provides the power necessary to let you build
semantic templates effectively with no frustration.
Mustache templates are compatible with Handlebars, so you can
take a Mustache template, import it into Handlebars, and start
taking advantage of the extra Handlebars features.
Handlebars templates look like regular HTML, with embedded
handlebars expressions.
<div class="entry">
<h1>{{title}}</h1>
<div class="body">
{{body}}
</div>
</div>
A handlebars expression is a {{, some contents,
followed by a }}
Learn More: Expressions
You can deliver a template to the browser by including it
in a <script> tag.
<script id="entry-template" type="text/x-handlebars-template">
template content
</script>
Compile a template in JavaScript by using
Handlebars.compile
var source = $("#entry-template").html();
var template = Handlebars.compile(source);
It is also possible to precompile your templates. This will
result in a smaller required runtime library and significant
savings from not having to compile the template in the
browser. This can be especially important when working with
mobile devices.
Learn More: Precompilation
Get the HTML result of evaluating a Handlebars template by
executing the template with a context.
var context = {title: "My New Post", body: "This is my first post!"}
var html = template(context);
results in
<div class="entry">
<h1>My New Post</h1>
<div class="body">
This is my first post!
</div>
</div>
Handlebars HTML-escapes values returned by a {{expression}}.
If you don't want Handlebars to escape a value, use the "triple-stash".
<div class="entry">
<h1>{{title}}</h1>
<div class="body">
{{{body}}}
</div>
</div>
with this context:
{
title: "All about <p> Tags",
body: "<p>This is a post about <p> tags</p>"
}
results in:
<div class="entry">
<h1>All About <p> Tags</h1>
<div class="body">
<p>This is a post about <p> tags</p>
</div>
</div>
Handlebars will not escape a Handlebars.SafeString.
If you write a helper that generates its own HTML, you will usually
want to return a new Handlebars.SafeString(result).
In such a circumstance, you will want to manually escape parameters.
Handlebars.registerHelper('link', function(text, url) {
text = Handlebars.Utils.escapeExpression(text);
url = Handlebars.Utils.escapeExpression(url);
var result = '<a href="' + url + '">' + text + '</a>';
return new Handlebars.SafeString(result);
});
This will escape the passed in parameters, but mark the response as
safe, so Handlebars will not try to escape it even if the "triple-stash"
is not used.
Block expressions allow you to define helpers that will invoke
a section of your template with a different context than the
current. Let's consider a helper that will generate an HTML list:
{{#list people}}{{firstName}} {{lastName}}{{/list}}
If we have the following context:
{
people: [
{firstName: "Yehuda", lastName: "Katz"},
{firstName: "Carl", lastName: "Lerche"},
{firstName: "Alan", lastName: "Johnson"}
]
}
we would create a helper named list to generate our
HTML list. The helper receives the people as its
first parameter, and an options hash as its second parameter.
The options hash contains a property named fn,
which you can invoke with a context just as you would invoke a
normal Handlebars template.
Handlebars.registerHelper('list', function(items, options) {
var out = "<ul>";
for(var i=0, l=items.length; i<l; i++) {
out = out + "<li>" + options.fn(items[i]) + "</li>";
}
return out + "</ul>";
});
When executed, the template will render:
<ul>
<li>Yehuda Katz</li>
<li>Carl Lerche</li>
<li>Alan Johnson</li>
</ul>
Block helpers have more features, such as the ability to create an
else section (used, for instance, by the built-in if
helper).
Since the contents of a block helper are escaped when you call
options.fn(context), Handlebars does not escape
the results of a block helper. If it did, inner content would
be double-escaped!
Learn More: Block Helpers
Handlebars supports simple paths, just like Mustache.
<p>{{name}}</p>
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!"
};
This makes it possible to use Handlebars templates with
more raw JSON objects.
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.
Handlebars also allows for name conflict resolution between helpers and
data fields via a this reference:
<p>{{./name}} or {{this/name}} or {{this.name}}</p>
Any of the above would cause the name field on the
current context to be used rather than a helper of the same name.
You can use comments in your handlebars code just as you would in your
code. Since there is generally some level of logic, this is a good
practice.
<div class="entry">
{{! only output this author names if an author exists }}
{{#if author}}
<h1>{{firstName}} {{lastName}}</h1>
{{/if}}
</div>
The comments will not being in the resulting output. If you'd like the
comments to show up. Just use html comments, and they will be output.
<div class="entry">
{{! This comment will not be in the output }}
</div>
Handlebars helpers can be accessed from any context in a template.
You can register a helper with the Handlebars.registerHelper method.
<div class="post">
<h1>By {{fullName author}}</h1>
<div class="body">{{body}}</div>
<h1>Comments</h1>
{{#each comments}}
<h2>By {{fullName author}}</h2>
<div class="body">{{body}}</div>
{{/each}}
</div>
when using this context and helpers:
var context = {
author: {firstName: "Alan", lastName: "Johnson"},
body: "I Love Handlebars",
comments: [{
author: {firstName: "Yehuda", lastName: "Katz"},
body: "Me too!"
}]
};
Handlebars.registerHelper('fullName', function(person) {
return person.firstName + " " + person.lastName;
});
results in:
<div class="post">
<h1>By Alan Johnson</h1>
<div class="body">I Love Handlebars</div>
<h1>Comments</h1>
<h2>By Yehuda Katz</h2>
<div class="body">Me Too!</div>
</div>
Helpers receive the current context as the this context
of the function.
<ul>
{{#each items}}
<li>{{agree_button}}</li>
{{/each}}
</ul>
when using this context and helpers:
var context = {
items: [
{name: "Handlebars", emotion: "love"},
{name: "Mustache", emotion: "enjoy"},
{name: "Ember", emotion: "want to learn"}
]
};
Handlebars.registerHelper('agree_button', function() {
return new Handlebars.SafeString(
"<button>I agree. I " + this.emotion + " " + this.name + "</button>"
);
});
results in:
<ul>
<li><button>I agree. I love Handlebars</button></li>
<li><button>I agree. I enjoy Mustache</button></li>
<li><button>I agree. I want to learn Ember</button></li>
</ul>
If your helper returns HTML that you do not want escaped, make sure
to return a new Handlebars.SafeString.
Normally, Handlebars templates are evaluated against the context
passed into the compiled method.
var source = "<p>{{lastName}}, {{firstName}}</p>";
var template = Handlebars.compile(source);
template({firstName: "Alan", lastName: "Johnson"});
results in
<p>Johnson, Alan</p>
You can shift the context for a section of a template by using
the built-in with block helper.
<div class="entry">
<h1>{{title}}</h1>
{{#with author}}
<h2>By {{firstName}} {{lastName}}</h2>
{{/with}}
</div>
when used with this context:
{
title: "My first post!",
author: {
firstName: "Charles",
lastName: "Jolley"
}
}
will result in:
<div class="entry">
<h1>My first post!</h1>
<h2>By Charles Jolley</h2>
</div>
You can iterate over a list using the built-in each
helper. Inside the block, you can use this to reference
the element being iterated over.
<ul class="people_list">
{{#each people}}
<li>{{this}}</li>
{{/each}}
</ul>
when used with this context:
{
people: [
"Yehuda Katz",
"Alan Johnson",
"Charles Jolley"
]
}
will result in:
<ul class="people_list">
<li>Yehuda Katz</li>
<li>Alan Johnson</li>
<li>Charles Jolley</li>
</ul>
You can use the this expression in any context to reference
the current context.
You can use the if helper to conditionally render a block. If
its argument returns false, undefined, null,
"" or [] (a "falsy" value), Handlebars will not
render the block.
<div class="entry">
{{#if author}}
<h1>{{firstName}} {{lastName}}</h1>
{{/if}}
</div>
when used with an empty ({}) context, will result in:
<div class="entry">
</div>
When using a block expression, you can specify a template section to
run if the expression returns a falsy value. The section, marked by
{{else}} is called an "else section".
<div class="entry">
{{#if author}}
<h1>{{firstName}} {{lastName}}</h1>
{{else}}
<h1>Unknown Author</h1>
{{/if}}
</div>
You can use the unless helper as the inverse of the
if helper. Its block will be rendered if the expression
returns a falsy value.
<div class="entry">
{{#unless license}}
<h3 class="warning">WARNING: This entry does not have a license!</h3>
{{/unless}}
</div>
If looking up license under the current context returns a
falsy value, Handlebars will render the warning. Otherwise, it will render
nothing.
The log helper allows for logging of context state while executing
a template.
{{log "Look at me!"}}
Delegates to Handlebars.logger.log which may
be overriden to perform custom logging.