Handlebars provides the power necessary to let you build semantic templates effectively with no frustration.
Handlebars 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.
<div class="entry"> <h1>{{title}}</h1> <div class="body"> {{body}} </div> </div>
{{, some contents,
followed by a }}
<script> tag.
<script id="entry-template" type="text/x-handlebars-template"> <div class="entry"> <h1>{{title}}</h1> <div class="body"> {{body}} </div> </div> </script>
Handlebars.compile
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);
<div class="entry"> <h1>My New Post</h1> <div class="body"> This is my first post! </div> </div>Learn More: Execution
{{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>
{
title: "All about <p> Tags",
body: "<p>This is a post about <p> tags</p>"
}
<div class="entry"> <h1>All About <p> Tags</h1> <div class="body"> <p>This is a post about <p> tags</p> </div> </div>
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); });
# preceeding
the helper name and require a matching closing mustache, /, of the
same name.
{{#list people}}{{firstName}} {{lastName}}{{/list}}
{
people: [
{firstName: "Yehuda", lastName: "Katz"},
{firstName: "Carl", lastName: "Lerche"},
{firstName: "Alan", lastName: "Johnson"}
]
}
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>"; });
<ul> <li>Yehuda Katz</li> <li>Carl Lerche</li> <li>Alan Johnson</li> </ul>
else section (used, for instance, by the built-in if
helper).
options.fn(context), Handlebars does not escape
the results of a block helper. If it did, inner content would
be double-escaped!
<p>{{name}}</p>
<div class="entry"> <h1>{{title}}</h1> <h2>By {{author.name}}</h2> <div class="body"> {{body}} </div> </div>
var context = { title: "My First Blog Post!", author: { id: 47, name: "Yehuda Katz" }, body: "My first post. Wheeeee!" };
../ 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>
../ 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.
this reference:
<p>{{./name}} or {{this/name}} or {{this.name}}</p>
name field on the
current context to be used rather than a helper of the same name.
{{!-- --}} or {{! }}.
<div class="entry"> {{!-- only output this author names if an author exists --}} {{#if author}} <h1>{{firstName}} {{lastName}}</h1> {{/if}} </div>
<div class="entry"> {{! This comment will not be in the output }} <!-- This comment will be in the output --> </div>
}} or other handlebars
tokens should use the {{!-- --}} syntax.
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>
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; });
<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>
this context
of the function.
<ul> {{#each items}} <li>{{agree_button}}</li> {{/each}} </ul>
var context = { items: [ {name: "Handlebars", emotion: "love"}, {name: "Mustache", emotion: "enjoy"}, {name: "Ember", emotion: "want to learn"} ] }; Handlebars.registerHelper('agree_button', function() { var emotion = Handlebars.escapeExpression(this.emotion), name = Handlebars.escapeExpression(this.name); return new Handlebars.SafeString( "<button>I agree. I " + emotion + " " + name + "</button>" ); });
<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>
Handlebars.SafeString.
if conditional
and each iterator.