index.mustache revision 72db4a8f2c8f0f8edadfaa736288ed7dc2535d02
0N/AHandlebars is a simple template language inspired by <a href="http://mustache.github.com/">Mustache</a>. This component is a YUI port of the <a href="https://github.com/wycats/handlebars.js">original Handlebars project</a>.
0N/AThis guide covers the YUI port of Handlebars, which differs from the original Handlebars in only [[#Differences From Original Handlebars|a few minor ways]] and is kept closely in sync with the original. The official Handlebars documentation can be found at <a href="http://handlebarsjs.com/">handlebarsjs.com</a>.
176N/AA Handlebars template is just some text that contains Handlebars [[#basic expressions|expressions]] like `\{{foo}}`. The text can be plain text, HTML, or anything else, although in most cases Handlebars is used to generate HTML. Handlebars doesn't actually care what format the document is, so it can be used for a wide variety of tasks.
508N/AWhen a template is rendered, expressions are evaluated and replaced with data. [[#Block expressions]] can be used for iteration, simple if/else branching, and executing [[#helper functions]], but otherwise Handlebars is completely logic-less. This makes it ideal for separating content from functionality.
176N/A<script id="list-template" type="text/x-handlebars-template">
25N/AWrapping the template in a `<script>` element with `type="text/x-handlebars-template"` is an easy way to put it in an HTML page and later render it on the client. The browser won't recognize the `text/x-handlebars-template` type, so it won't try to execute the script. When we're ready, we can extract the template and render it using `Y.Handlebars`. This is much more maintainable than storing templates in JavaScript strings.
615N/A template = Y.Handlebars.compile(source),
212N/A {name: 'pie', url: 'http://pieisgood.org/'},
212N/A {name: 'mountain dew', url: 'http://www.mountaindew.com/'},
154N/A {name: 'kittens', url: 'http://www.flickr.com/search/?q=kittens'},
0N/A {name: 'rainbows', url: 'http://www.youtube.com/watch?v=OQSNhk5ICTI'}
25N/A <li><a href="http://pieisgood.org/">pie</a></li>
56N/A <li><a href="http://www.mountaindew.com/">mountain dew</a></li>
56N/A <li><a href="http://www.flickr.com/search/?q=kittens">kittens</a></li>
25N/A <li><a href="http://www.youtube.com/watch?v=OQSNhk5ICTI">rainbows</a></li>
0N/AYou can re-render the template at any time simply by executing the stored `template` function again and passing in new data. Templates only need to be parsed once, which makes rendering a template multiple times very fast.
0N/A {name: 'caffeine', url: 'http://en.wikipedia.org/wiki/Caffeine'},
0N/A {name: 'git', url: 'http://git-scm.com/'},
0N/A {name: 'numberwang', url: 'http://www.youtube.com/watch?v=qjOZtWZ56lc'}
0N/AAlternatively, if you only need to render something once, you can use the convenient <a href="{{apiDocs}}/classes/Handlebars.html#method_render">`render()`</a> method to parse and render a template in a single step.
0N/Avar html = Y.Handlebars.render(source, {
0N/AA basic Handlebars expression starts with `\{{`, contains some text, and ends with `}}`. These delimiters are often referred to as "mustaches", since they look a little bit like fancy mustaches if you turn your head sideways, squint a bit, and use your imagination. When a template is rendered, Handlebars will replace expressions with rendered data.
0N/AThis tells Handlebars, "If there's a [[#helper functions|helper function]] named 'title', execute it and insert its return value here. Otherwise, look up the value of the `title` property in the current [[#contexts & paths|context]] and insert it here". The expression will be replaced with the referenced value, or an empty string if there's no helper function named "title" and the current context's `title` property is falsy, an empty array, or doesn't exist.
0N/ABy default, content rendered using a double-mustache expression like `\{{foo}}` will automatically be HTML-escaped for safety. To render unescaped HTML output, use a triple-mustache expression like `\{{{foo}}}`. Only use a triple-mustache expression for content you trust! Never use it to render unfiltered user input.
0N/AAll expressions are evaluated relative to the current <strong>context</strong>. The default context for a template is the data object passed in when the template is rendered.
0N/A url: 'http://blog.example.com'
0N/AYou can change the context using a [[#block expressions|block expression]]. Inside the block, the context will be set to the value referenced in the block's opening tag.
0N/ACertain [[#Built-in Block Helpers|block helpers]] also change the context within the block. For example, when iterating over an array of items using `\{{#each items}} ... \{{/each}}` or `\{{#items}} ... \{{/items}}`, the context inside the block will be set to the current item.
0N/AThe special expression `\{{.}}` always evaluates to the current context, sort of like `this` in JavaScript. In fact, `\{{.}}` and `\{{this}}` do exactly the same thing! This is especially useful when iterating over an array of strings, since it allows you to output each string value.
0N/AUsing blocks to change the context is optional. Expressions can reference deeply-nested properties using dot notation:
0N/A <h2>\{{article.title}}</h2>
0N/ANote that `../` references the parent scope, but not necessarily the previous level in the context hierarchy. Block helpers can invoke a block with any context, so a purely hierarchical reference wouldn't make much sense.
0N/ABlock expressions are used to change the current context or to execute helper functions that accept a block of content and perform an action on that content before rendering it. A block expression starts with an opening tag prefixed by `#`, contains some content, and ends with a closing tag prefixed by `/`, similar to an HTML element.
0N/AThe following example uses the [[#built-in block helpers|built-in]] `each` helper to iterate over an array named `gadgets` and render the block's content in the context of each item in the array.
The `each` helper is so useful that Handlebars will actually use it as the default helper if you create a block expression with an identifier that points to an array value. So we could also write the template above like this and get the same result:
If a block expression refers to an empty array, a falsy value, or a value that doesn't exist in the current context, the block's contents won't be rendered.
A block expression that refers to a non-array value such as an object or string will change the context to that value inside the block. See [[#Contexts & Paths]] for an example of this.
Handlebars includes two [[#built-in block helpers]] that provide simple conditional branching: `if` and `unless`.
The `if` block helper accepts a single parameter, which may be either a literal value or a reference to a value. If the value is truthy and not an empty array, the contents of the block will be rendered. If an optional `else` block is provided, its contents will be rendered if the value is falsy or an empty array. Inside an `if` or `else` block, the context remains the same as it was outside the block.
In order to prevent templates from becoming bogged down with logic that should be implemented in another layer of the application, the `if` helper only supports simple true/false logic based on a single value. It doesn't support comparisons or logical operators like `&&` and `||`.
The `unless` block helper does exactly the opposite of the `if` helper: it renders the contents of the block if the provided value is falsy or an empty array.
An expression beginning with `\{{!` is treated as a comment and won't show up in the rendered output.
Unfortunately, Handlebars doesn't ignore expressions inside comments, so you can't actually comment out an expression.
An expression like `\{{> partialName}}` will render the named partial template at that position in the output, inheriting the current data context. A partial is a reusable template that's registered using the <a href="{{apiDocs}}/classes/Handlebars.html#method_registerPartial">`registerPartial()`</a> method.
Helper functions are functions that are registered with the Handlebars runtime using the <a href="{{apiDocs}}/classes/Handlebars.html#method_registerHelper">`registerHelper()`</a> method and can then be called from within a template at render-time. They can be used to transform text; implement iteration, branching logic, and other control flows; and perform a variety of other tasks.
A helper function can accept parameters and even entire blocks of template content. Here's how you might call a simple inline helper to render an HTML link, passing in the link text and URL:
\{{link "Handlebars docs" "http://handlebarsjs.com"}}
Block helpers have a slightly different syntax, using an opening and closing tag to delimit an entire block of template content. The helper name is specified in the opening and closing tags of the block:
Helper functions are executed when a template is rendered, not when it's compiled. This allows helper functions to take advantage of the state of the rendering environment (since a template may have been pre-compiled somewhere else), and to return different content even when the same template is rendered multiple times.
To define a custom helper function, call the <a href="{{apiDocs}}/classes/Handlebars.html#method_registerHelper">`registerHelper()`</a> method and provide a name and a function to execute when the helper is called. The function may accept any number of arguments from the template, which may be provided either as literal values or as references to data properties. The final argument passed to the function will always be an `options` object (more on this [[#hash arguments|later]]).
Y.Handlebars.registerHelper('link', function (text, url) {
<li>\{{{link "Pie" "http://pieisgood.org/"}}}</li>
<li><a href="http://pieisgood.org/">Pie</a></li>
<li><a href="http://www.flickr.com/search/?q=kittens">Kittens</a></li>
Notice the use of the triple-mustache for the `\{{{link}}}` expressions? That was necessary in order to prevent the helper's return value from being HTML-escaped. As an alternative to using a triple-mustache, we could modify the helper to return an instance of `Y.Handlebars.SafeString`, which will bypass HTML escaping even when used with a double-mustache expression.
Y.Handlebars.registerHelper('link', function (text, url) {
text = Y.Escape.html(text);
url = Y.Escape.html(url);
return new Y.Handlebars.SafeString('<a href="' + url + '">' + text + '</a>');
Now we can simply use `\{{link "Text" "http://example.com/"}}` to call the helper, and we don't need to worry about escaping in the template itself since we know the helper will take care of it.
In the example above, we created a helper that accepts two unnamed arguments. This works fine for simple helpers, but for a helper that needs to accept a lot of arguments, it can quickly become painful to remember which arguments go where, and what each one means. Luckily, Handlebars supports a special syntax for calling a helper function with a hash of named parameters.
The final argument passed to a helper function is always a special `options` object. The `options.hash` property is an object hash that contains any named parameters that were passed from the template.
Y.Handlebars.registerHelper('link', function (options) {
return new Y.Handlebars.SafeString('<a href="' + url + '">' + text + '</a>');
In the template, pass hash arguments as key/value pairs delimited by `=` and separated by a space. Keys must be simple identifiers. Values may be literal values (strings, bools, integers) or references to data properties.
<li>\{{link text="Pie" url="http://pieisgood.org/"}}</li>
Y.Handlebars.registerHelper('link', function (text, options) {
text = Y.Escape.html(text);
return new Y.Handlebars.SafeString('<a href="' + url + '">' + text + '</a>');
<li>\{{link "Pie" url="http://pieisgood.org/"}}</li>
The `options` object passed to a block helper function contains an `fn` property, which is a function that accepts a context as an argument and returns a string containing the rendered contents of the block.
The `options` object passed to a block helper function also contains an `inverse` property. This is a function that accepts a context just like the `fn` property, except that it renders the block following an `else` statement. If there isn't an `else` statement, the `inverse` function will be a noop.
The return value of a block helper is not automatically HTML-escaped, but the return value of `options.fn()` <em>is</em> automatically escaped. This ensures that block helpers don't return double-escaped content.
Y.Handlebars.registerHelper('gamera', function (options) {
Here's how Handlebars implements its own [[#if|`if`]] block helper. The `options.inverse()` function makes it possible to render the contents of an `else` block if one is provided.
Y.Handlebars.registerHelper('if', function (condition, options) {
return options.fn(this);
return options.inverse(this);
The `each` helper iterates over an array. The block will be rendered once for each item, and its context will be set to the current item.
If you create a block expression with an identifier that points to an array value, Handlebars will automatically use the `each` helper to iterate over that array, so we could rewrite the template above like this and get the same result:
The `with` block helper renders the given block in a different context. This can save you some typing in a template that will render a lot of namespaced data.
If you create an expression with an identifier that points to an object value, Handlebars will automatically use the `with` helper to render the block in the context of that object, so we could rewrite the template above like this and get the same result:
A partial is like a mini-template that can be called from a larger template. Partials are often used to render frequently-used chunks of content, such as a header, footer, or a common view of some data.
Partials are registered with Handlebars through the <a href="{{apiDocs}}/classes/Handlebars.html#method_registerPartial">`registerPartial()`</a> method. Once registered, a partial can be referenced from a template using an expression like `\{{> partialName }}`. Partials may be registered as string templates or as compiled template functions.
Y.Handlebars.registerPartial('header', '<h1>{{title}}</h1>');
Y.Handlebars.registerPartial('footer', '<p>Copyright (c) 2012 by Me.</p>');
When you plan to compile and render Handlebars templates on the client, the easiest way to deliver templates to the browser is to include them in the HTML page inside a `<script>` element with the attribute `type="text/x-handlebars-template"`. The browser won't recognize this type, so it won't try to execute the contents of the `<script>` node.
<script id="list-template" type="text/x-handlebars-template">
This makes it easy and convenient to maintain your templates right alongside the HTML in which they'll be rendered, which is much nicer than storing them in big ugly strings inside your JavaScript files.
When you're ready to render a template, just pull its text out of the `<script>` node, render it, and append the resulting HTML to the page wherever you want it.
var source = Y.one('#list-template').get('text'),
template = Y.Handlebars.compile(source),
{name: 'pie', url: 'http://pieisgood.org/'},
{name: 'mountain dew', url: 'http://www.mountaindew.com/'},
{name: 'kittens', url: 'http://www.flickr.com/search/?q=kittens'},
{name: 'rainbows', url: 'http://www.youtube.com/watch?v=OQSNhk5ICTI'}
Y.one('body').append(html);
Handlebars templates must be compiled before they can be rendered. One benefit of this is that a template only needs to be compiled once, and it can then be rendered multiple times without being recompiled. Templates can even be [[#precompiling templates|precompiled]] on the server or on the command line and then rendered on the client for optimal performance.
To compile a template string, pass it to the <a href="{{apiDocs}}/classes/Handlebars.html#method_compile">`Y.Handlebars.compile()`</a> method. You'll get back a function.
var template = Y.Handlebars.compile('My favorite food is \{{food}}.');
When you're ready to render the template, execute the function and pass in some data. You'll get back a rendered string.
You can re-render the template at any time just by calling the function again. You can even pass in completely different data.
If you don't plan to use a template more than once, you can compile and render it in a single step with <a href="{{apiDocs}}/classes/Handlebars.html#method_render">`Y.Handlebars.render()`</a>.
output = Y.Handlebars.render('My favorite food is \{{food}}.', {food: 'pie'});
Since Handlebars templates can be compiled and rendered in separate steps, it's possible to precompile a template for use later. You can precompile a template into raw JavaScript on the server or even on the command line, serve this precompiled JavaScript template to the client, and then render it on the client using any data the client has at its disposal.
The main benefit of precompilation is performance. Not only does the client not need to go through the compile step, you don't even have to load the Handlebars compiler on the client! All the client needs in order to render a precompiled template is a very small (about 1KB minified and gzipped) piece of JavaScript provided by the `handlebars-base` module.
To precompile Handlebars templates on the server using <a href="http://nodejs.org/">Node.js</a>, first install the YUI <a href="http://npmjs.org/">npm</a> module by running the following in a terminal from the directory that contains your server application (this assumes you already have Node and npm installed):
This will install the `yui` npm module in the current directory and make it available to your application.
Next, in your application code, call the <a href="{{apiDocs}}/classes/Handlebars.html#method_precompile">`precompile()`</a> method to precompile a Handlebars template. It will return a string containing JavaScript code.
var Handlebars = require('yui/handlebars').Handlebars;
var precompiled = Handlebars.precompile('My favorite food is \{{food}}.');
function (Handlebars,depth0,helpers,partials,data) {\n helpers = helpers || Handlebars.helpers;\n var buffer = "", stack1, foundHelper, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression;\n\n\n buffer += "My favorite food is ";\n foundHelper = helpers.food;\n stack1 = foundHelper || depth0.food;\n if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }\n else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "food", { hash: {} }); }\n buffer += escapeExpression(stack1) + ".";\n return buffer;}
You can now serve this precompiled JS to the client in whatever way makes the most sense for your application. On the client, load the `handlebars-base` YUI module and pass the precompiled template to the <a href="{{apiDocs}}/classes/Handlebars.html#method_template">`Y.Handlebars.template()`</a> method to convert it into a renderable template function.
Here's a simple <a href="http://expressjs.com/">Express</a> app that precompiles a template on the server and renders it on the client:
#!/usr/bin/env node
var Handlebars = require('yui/handlebars').Handlebars,
precompiled = Handlebars.precompile('My favorite food is \{{food}}.');
app.get('/', function (req, res) {
'var template = Y.Handlebars.template(' + precompiled + ');' +
'Y.one("body").append(template({food: "pie"}));' +
app.listen(7000);
To see this simple server in action, save it to a file, install Express and YUI by running `npm i express yui`, then execute the file with Node.js and browse to <a href="http://localhost:7000/" target="_blank">http://localhost:7000/</a>.
The original Handlebars project provides a Node.js-based Handlebars command-line application that can be installed via npm and used to precompile Handlebars template files. Since the precompiled templates produced by the original Handlebars are compatible with YUI Handlebars, this is a great way to precompile your Handlebars templates manually or as part of a build process.
First, you'll need to install <a href="http://nodejs.org/">Node.js</a> and <a href="http://npmjs.org/">npm</a> if you haven't already. See their respective websites for instructions.
Next, install the Handlebars npm module. Note that this program is maintained by the maintainers of the <a href="https://github.com/wycats/handlebars.js">original Handlebars project</a>, so there's a chance it could change or break compatibility with YUI Handlebars without notice.
This will compile a template to a JavaScript file which you can load on your page. You could render it like this:
// Create a global Handlebars variable that points to Y.Handlebars. This is
Y.error('Template failed to load: ' + err);
var output = Y.Handlebars.templates['my-template']({food: 'pie'});
Y.one('#content').append(output);
The YUI Handlebars component is mostly just a YUI wrapper around the <a href="https://github.com/wycats/handlebars.js">original Handlebars code</a>. It's kept closely in sync with the latest code from the upstream Handlebars project, and our intent is to ensure that YUI Handlebars and original Handlebars can be used interchangeably to render the same templates. To see what upstream Handlebars version YUI uses, inspect `Y.Handlebars.VERSION`.
YUI Handlebars is a first-class YUI module intended to be loaded via `YUI().use()` or as a dependency of a module created via `YUI.add()`. Like all YUI modules, it adds its API to the `Y` namespace, so the YUI Handlebars object is `Y.Handlebars` instead of the global `Handlebars` namespace used by the original Handlebars.
YUI Handlebars uses YUI's own `Y.Escape.html()` method to escape HTML, and the `Y.Lang.isEmpty()` and `Y.Lang.isArray()` methods to determine whether a value is empty or an array.
In escaped expressions like `\{{foo}}`, YUI Handlebars escapes all `&` characters, even when they're part of an existing HTML entity like `&`. Original Handlebars doesn't double-escape existing HTML entities.
This change was made to ensure consistency and safety—this way you always know that all the contents of a value rendered by an escaped expression will truly be escaped, even if that means some characters will be double-escaped. This is especially important in cases where double-escaping is desired, such as when attempting to display the literal string `&` in a code example or documentation (like this user guide!).
The `Y.Handlebars.log()` function and the `log` helper call `Y.log()` under the hood. The log implementation in original Handlebars is a noop that's meant to be overridden.
YUI Handlebars appends a "-yui" suffix to the `Y.Handlebars.VERSION` property.