Handlebars.
js: Minimal Templating on Steroids
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.
Getting Started
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 }}
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 [Link]
var source = $("#entry-template").html(); var template = [Link](source);
In a future release, it will be possible to precompile Handlebars templates into JavaScript les to save time on the client.
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>
1 of 8
[Link]: Minimal Templating on Steroids
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 [Link] . If you write a helper that generates its own HTML, you will usually want to return a new [Link](result) . In such a circumstance, you will want to manually escape parameters.
[Link]('link', function(text, url) { text = [Link](text); url = [Link](url); var result = '<a href="' + url + '">' + text + '</a>'; return new [Link](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
Block expressions allow you to dene 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}}
2 of 8
[Link]: Minimal Templating on Steroids
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 rst parameter, and Function as its second parameter. Invoke the function with a context just as you would invoke a normal Handlebars template.
[Link]('list', function(items, fn) { var out = "<ul>"; for(var i=0, l=[Link]; i<l; i++) { out = out + "<li>" + 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).
Built-In Block Helpers
The with Block Helper
Normally, Handlebars templates are evaluated against the context passed into the compiled method.
var source = "<p>{{lastName}}, {{firstName}}</p>"; var template = [Link](source); template({firstName: "Alan", lastName: "Johnson"});
results in
<p>Johnson, Alan</p>
3 of 8
[Link]: Minimal Templating on Steroids
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>
The each block helper
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:
4 of 8
[Link]: Minimal Templating on Steroids
<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.
The if block helper
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>
The unless block helper
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.
Handlebars Paths
5 of 8
[Link]: Minimal Templating on Steroids
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 {{[Link]}}</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.
Helpers
6 of 8
[Link]: Minimal Templating on Steroids
Handlebars helpers can be accessed from any context in a template. You can register a helper with the [Link] 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}}</h2> {{/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!" }] }; [Link]('fullName', function(person) { return [Link] + " " + [Link]; });
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!</h2> </div>
Helpers receive the current context as the this context of the function.
<ul> {{#each items}} <li>{{agree_button}}</li> {{/each}} </ul>
7 of 8
[Link]: Minimal Templating on Steroids
when using this context and helpers:
var context = { items: [ {name: "Handlebars", emotion: "love"}, {name: "Mustache", emotion: "enjoy"}, {name: "SproutCore", emotion: "want to learn"} ] }; [Link]('agree_button', function() { return "<button>I agree. I " + [Link] + " " + [Link] + "</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 SproutCore</button></li> </ul>
8 of 8