303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<style scoped>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove.handlebars-code pre.code {
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove height: 100%;
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove.handlebars-code td,
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove.handlebars-code th {
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove background: #fff;
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove padding: 0 0 0 12px;
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove.handlebars-code td:first-child,
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove.handlebars-code th:first-child { padding-left: 0; }
5de853af51191afb07d8df5e55dbdd2494eea9e7Ryan Grove<div class="intro">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveHandlebars 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>.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveThis 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>.
5de853af51191afb07d8df5e55dbdd2494eea9e7Ryan Grove{{>getting-started}}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<h2>Using Handlebars</h2>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<h3>Quick Start</h3>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan GroveA Handlebars template is just some text that contains Handlebars [[#basic expressions|expressions]] like `\{{foo}}`. Although most people use Handlebars to generate HTML, it can easily generate JSON, XML, YAML, or any other plain text format.</p>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan GroveWhen you render a template, Handlebars evaluates expressions and replaces them 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.
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan GroveFirst, you need to define a template string somewhere. Most template strings are long and contain lots of newlines and indentation, which makes them hard to read and maintain if you store them directly in JavaScript. A common pattern in apps that use Handlebars is to use <strong>micro-templating</strong>, which means embedding template strings in a static HTML document, wrapped in a `<script>` element with the attribute `type="text/x-handlebars-template"`. Thanks to the `type` attribute, the browser won't try to execute the script, and you can fetch the template string whenever you need it using `Y.one()`.
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan GroveHere's a simple micro-template that creates a list of links:
72db4a8f2c8f0f8edadfaa736288ed7dc2535d02Ryan Grove```handlebars
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<script id="list-template" type="text/x-handlebars-template">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <p>YUI is brought to you by:</p>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li><a href="\{{url}}">\{{name}}</a></li>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan GroveOnce you have a template string, the next step is to <strong>compile</strong> that string into a Handlebars template function. You can then <strong>render</strong> the template by passing a data object (also known as a [[#contexts & paths|context]]) into that function.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveYUI().use('handlebars', 'node-base', function (Y) {
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove // Extract the template string and compile it into a reusable function.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove var source = Y.one('#list-template').get('text'),
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove template = Y.Handlebars.compile(source),
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove // Render the template to HTML using the specified data.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove html = template({
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove {name: 'pie', url: 'http://pieisgood.org/'},
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove {name: 'mountain dew', url: 'http://www.mountaindew.com/'},
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove {name: 'kittens', url: 'http://www.flickr.com/search/?q=kittens'},
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove {name: 'rainbows', url: 'http://www.youtube.com/watch?v=OQSNhk5ICTI'}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove // Append the rendered template to the page.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove Y.one('body').append(html);
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan GroveAfter it's rendered and appended to the page, the output looks like this:
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<div class="example">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <p>YUI is brought to you by:</p>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li><a href="http://pieisgood.org/">pie</a></li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li><a href="http://www.mountaindew.com/">mountain dew</a></li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li><a href="http://www.flickr.com/search/?q=kittens">kittens</a></li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li><a href="http://www.youtube.com/watch?v=OQSNhk5ICTI">rainbows</a></li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveYou 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove// Re-render the template with new data. No need to parse the template again.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grovevar html = template({
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove {name: 'caffeine', url: 'http://en.wikipedia.org/wiki/Caffeine'},
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove {name: 'git', url: 'http://git-scm.com/'},
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove {name: 'numberwang', url: 'http://www.youtube.com/watch?v=qjOZtWZ56lc'}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveAlternatively, 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove// Parse and render a template in a single step.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grovevar html = Y.Handlebars.render(source, {
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove // ... data ...
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<h3>Template Syntax</h3>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<h4>Basic Expressions</h4>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveA 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveA simple Handlebars expression looks like this:
72db4a8f2c8f0f8edadfaa736288ed7dc2535d02Ryan Grove```handlebars
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<h1>\{{title}}</h1>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan GroveThis tells Handlebars:
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <li><p>If there's a [[#helper functions|helper function]] named "title", execute it and insert its return value here.</p></li>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <li><p>Otherwise, if there exists a `title` property in the current [[#contexts & paths|context]], and that property is not falsy or an empty array, insert its value here.</p></li>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <li><p>Otherwise, insert an empty string.</p></li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<h5>HTML Escaping</h5>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveBy 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.
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan GroveHandlebars also supports an alternative `\{{&foo}}` syntax to render unescaped content, but this syntax is less commonly used. That said, some people find it preferable to the triple-mustache syntax since it's easier to spot at a glance.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<h5>Contexts & Paths</h5>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveAll 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveHere's the default context used for the examples in the rest of this section:
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove title: 'AwesomeBlog',
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove title: 'My blog is awesome'
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveYou 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.
72db4a8f2c8f0f8edadfaa736288ed7dc2535d02Ryan Grove```handlebars
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<div class="header">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <h1><a href="\{{url}}">\{{title}}</a></h1>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<div class="content">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove \{{#article}}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <h2>\{{title}}</h2>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove \{{/article}}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveCertain [[#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.
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan GroveThe 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 [[#each|iterating over an array of strings]], since it allows you to output each string value.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveUsing blocks to change the context is optional. Expressions can reference deeply-nested properties using dot notation:
72db4a8f2c8f0f8edadfaa736288ed7dc2535d02Ryan Grove```handlebars
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<div class="content">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveThe special expression `../` references the current context's parent scope.
72db4a8f2c8f0f8edadfaa736288ed7dc2535d02Ryan Grove```handlebars
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<div class="content">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove \{{#article}}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <h2><a href="\{{../site.url}}/article/\{{id}}">\{{title}}</a></h2>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove \{{/article}}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveNote 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<h4>Block Expressions</h4>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan GroveBlock expressions are used to change the current [[#contexts & paths|context]] or to pass a block of content to a [[#helper functions|helper function]]. 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.
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan GroveThe following example uses the [[#each|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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<table class="handlebars-code">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <th>Template Source</th>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <th>Data</th>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <th>Output</th>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <td width="33%">
72db4a8f2c8f0f8edadfaa736288ed7dc2535d02Ryan Grove ```handlebars
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove \{{#each gadgets}}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li>\{{name}}</li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <td width="33%">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove {name: 'iPhone'},
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove {name: 'Android'},
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove {name: 'Windows Phone'}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <td width="33%">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li>iPhone</li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li>Android</li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li>Windows Phone</li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveThe `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:
72db4a8f2c8f0f8edadfaa736288ed7dc2535d02Ryan Grove```handlebars
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove\{{#gadgets}}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li>\{{name}}</li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove\{{/gadgets}}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveIf 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveA 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.
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove<h4>Built-in Block Helpers</h4>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan GroveHandlebars provides several built-in block helpers that are always available to templates.
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove<h5>each</h5>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan GroveThe `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.
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove<table class="handlebars-code">
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <th>Template Source</th>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <th>Data</th>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <th>Output</th>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <td width="33%">
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove ```handlebars
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <h1>Bands Ryan likes</h1>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove \{{#each bands}}
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <li>\{{.}}</li>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <td width="33%">
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove 'The Dandy Warhols',
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove 'The Brian Jonestown Massacre',
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove 'The Black Keys',
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove 'Black Rebel Motorcycle Club'
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <td width="33%">
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <h1>Bands Ryan likes</h1>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <li>The Dandy Warhols</li>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <li>The Brian Jonestown Massacre</li>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <li>The Black Keys</li>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <li>Black Rebel Motorcycle Club</li>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan GroveIf 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:
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove```handlebars
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove<h1>Bands Ryan likes</h1>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <li>\{{.}}</li>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove<h5>with</h5>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan GroveThe `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.
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove<table class="handlebars-code">
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <th>Template Source</th>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <th>Data</th>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <th>Output</th>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <td width="33%">
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove ```handlebars
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <p class="author">
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove \{{#with author}}
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove \{{firstName}} \{{lastName}}
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <td width="33%">
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove firstName: 'Ryan',
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove lastName: 'Grove'
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <td width="33%">
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove <p class="author">
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan GroveIf 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:
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove```handlebars
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove<p class="author">
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove \{{firstName}} \{{lastName}}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveThe `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.
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan GroveIn order to prevent templates from becoming bogged down with logic that should be implemented in JavaScript or in a helper function, the `if` helper only supports simple true/false logic based on a single value. It doesn't support comparisons or logical operators like `&&` and `||`.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<table class="handlebars-code">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <th>Template Source</th>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <th>Data</th>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <th>Output</th>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <td width="33%">
72db4a8f2c8f0f8edadfaa736288ed7dc2535d02Ryan Grove ```handlebars
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <h1>Currently online</h1>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove \{{#if users}}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li>\{{.}}</li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <td width="33%">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove 'Ryan Grove',
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove 'Eric Ferraiuolo',
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove 'Lucas Smith',
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <td width="33%">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <h1>Currently online</h1>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li>Ryan Grove</li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li>Eric Ferraiuolo</li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li>Lucas Smith</li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li>Dav Glass</li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveIf we empty the `users` array and re-render the template, the list won't be included in the output.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<table class="handlebars-code">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <th>Template Source</th>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <th>Data</th>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <th>Output</th>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <td width="33%">
72db4a8f2c8f0f8edadfaa736288ed7dc2535d02Ryan Grove ```handlebars
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <h1>Currently online</h1>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove \{{#if users}}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li>\{{.}}</li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <td width="33%">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <td width="33%">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <h1>Currently online</h1>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveWe can add an `else` block to display an informative message when no users are online.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<table class="handlebars-code">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <th>Template Source</th>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <th>Data</th>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <th>Output</th>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <td width="33%">
72db4a8f2c8f0f8edadfaa736288ed7dc2535d02Ryan Grove ```handlebars
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <h1>Currently online</h1>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove \{{#if users}}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li>\{{.}}</li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <p>Nobody's here!</p>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <td width="33%">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <td width="33%">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <h1>Currently online</h1>
b038370fb38fcc80c0c1fea5d88d8f63424cfc63Eric Ferraiuolo <p>Nobody's here!</p>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<h5>unless</h5>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveThe `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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<table class="handlebars-code">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <th>Template Source</th>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <th>Data</th>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <th>Output</th>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <td width="33%">
72db4a8f2c8f0f8edadfaa736288ed7dc2535d02Ryan Grove ```handlebars
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <h1>Currently online</h1>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove \{{#unless users}}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <p>Nobody's here!</p>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li>\{{.}}</li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove \{{/unless}}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <td width="33%">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove 'Ryan Grove',
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove 'Eric Ferraiuolo',
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove 'Lucas Smith',
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <td width="33%">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <h1>Currently online</h1>
b038370fb38fcc80c0c1fea5d88d8f63424cfc63Eric Ferraiuolo <li>Ryan Grove</li>
b038370fb38fcc80c0c1fea5d88d8f63424cfc63Eric Ferraiuolo <li>Eric Ferraiuolo</li>
b038370fb38fcc80c0c1fea5d88d8f63424cfc63Eric Ferraiuolo <li>Lucas Smith</li>
b038370fb38fcc80c0c1fea5d88d8f63424cfc63Eric Ferraiuolo <li>Dav Glass</li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<h4>Comment Expressions</h4>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveAn expression beginning with `\{{!` is treated as a comment and won't show up in the rendered output.
72db4a8f2c8f0f8edadfaa736288ed7dc2535d02Ryan Grove```handlebars
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove\{{! I'm a Handlebars comment! I won't show up in rendered output. }}
72db4a8f2c8f0f8edadfaa736288ed7dc2535d02Ryan Grove<!-- I'm an HTML comment! I will show up in rendered output. -->
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveMulti-line comments work too.
72db4a8f2c8f0f8edadfaa736288ed7dc2535d02Ryan Grove```handlebars
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove I'm a multi-line comment!
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveUnfortunately, Handlebars doesn't ignore expressions inside comments, so you can't actually comment out an expression.
72db4a8f2c8f0f8edadfaa736288ed7dc2535d02Ryan Grove```handlebars
72db4a8f2c8f0f8edadfaa736288ed7dc2535d02Ryan Grove<!-- This won't work (it'll leave a trailing "}}" behind) -->
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove\{{! \{{expression}} }}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<h4>Partial Expressions</h4>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveAn 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveSee the [[#Partials]] section of this guide for more details on creating and using partials.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<h3>Helper Functions</h3>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan GroveHelper functions (often referred to simply as "helpers") 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. Helper functions can transform text, iterate over arbitrary data, implement branching logic, and more.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveA 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:
72db4a8f2c8f0f8edadfaa736288ed7dc2535d02Ryan Grove```handlebars
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove\{{link "Handlebars docs" "http://handlebarsjs.com"}}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveBlock 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:
72db4a8f2c8f0f8edadfaa736288ed7dc2535d02Ryan Grove```handlebars
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove\{{#list contents}}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove \{{link text url}}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveMany of Handlebars' own features are implemented as [[#Built-in Block Helpers]].
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveHelper 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<h4>Defining Custom Helpers</h4>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveTo 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]]).
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<h5>Basic Helpers</h5>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveHere's a simple helper that takes two parameters and spits out an HTML link.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove// Register a \{{{link}}} helper for creating HTML links.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveY.Handlebars.registerHelper('link', function (text, url) {
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove return '<a href="' + url + '">' + text + '</a>';
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveWe can use this helper to render the following template:
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<p style="margin-bottom: -1em;">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<strong>Template Source</strong>
72db4a8f2c8f0f8edadfaa736288ed7dc2535d02Ryan Grove```handlebars
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li>\{{{link "Pie" "http://pieisgood.org/"}}}</li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<p style="margin-bottom: -1em;">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<strong>Data</strong>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove text: "Kittens",
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<p style="margin-bottom: -1em;">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<strong>Output</strong>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li><a href="http://pieisgood.org/">Pie</a></li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li><a href="http://www.flickr.com/search/?q=kittens">Kittens</a></li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveNotice 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove// Register a \{{link}} helper for creating HTML links. The return value of this
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove// helper will never be automatically HTML-escaped, so the helper does its own
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove// internal escaping.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveY.Handlebars.registerHelper('link', function (text, url) {
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove return new Y.Handlebars.SafeString('<a href="' + url + '">' + text + '</a>');
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveNow 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<h5>Hash Arguments</h5>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan GroveIn the example above, we created a helper that accepts two unnamed arguments. Unnamed arguments work fine for simple helpers, but you can also choose to supply a helper function with a hash of named parameters. This may be more intuitive if your helper accepts a lot of options.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveThe 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove// Register a \{{link}} helper that accepts a hash of named parameters instead
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove// of individual arguments.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveY.Handlebars.registerHelper('link', function (options) {
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove return new Y.Handlebars.SafeString('<a href="' + url + '">' + text + '</a>');
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveIn 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.
72db4a8f2c8f0f8edadfaa736288ed7dc2535d02Ryan Grove```handlebars
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li>\{{link text="Pie" url="http://pieisgood.org/"}}</li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li>\{{link text=kittens.text url=kittens.url}}</li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveA helper function can even accept a combination of standard arguments and hash arguments.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove// Register a \{{link}} helper that accepts a combination of standard args and
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove// hash arguments.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveY.Handlebars.registerHelper('link', function (text, options) {
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove return new Y.Handlebars.SafeString('<a href="' + url + '">' + text + '</a>');
72db4a8f2c8f0f8edadfaa736288ed7dc2535d02Ryan Grove```handlebars
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <li>\{{link "Pie" url="http://pieisgood.org/"}}</li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<h5>Block Helpers</h5>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveA block helper works similarly to a basic helper, with a couple of differences:
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveHere's a simple block helper that wraps its contents in a `<p>` element:
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveY.Handlebars.registerHelper('gamera', function (options) {
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove return '<p class="' + this.animal + '">' + options.fn(this) + '</p>';
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<table class="handlebars-code">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <th>Template Source</th>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <th>Data</th>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <th>Output</th>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <td width="33%">
72db4a8f2c8f0f8edadfaa736288ed7dc2535d02Ryan Grove ```handlebars
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <p>Gamera is really neat!</p>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove \{{#gamera}}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove He is made of \{{animal}} meat!
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove \{{/gamera}}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <td width="33%">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove animal: 'turtle'
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <td width="33%">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <p>Gamera is a really neat!</p>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <p class="turtle">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove He is made of turtle meat!
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveHere'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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveY.Handlebars.registerHelper('if', function (condition, options) {
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove if (condition) {
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove return options.fn(this);
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<h3>Partials</h3>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveA 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GrovePartials 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveA partial will inherit the current context of the position at which it's included.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove// Register a couple of reusable partials.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveY.Handlebars.registerPartial('header', '<h1>{{title}}</h1>');
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveY.Handlebars.registerPartial('footer', '<p>Copyright (c) 2012 by Me.</p>');
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<table class="handlebars-code">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <th>Template Source</th>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <th>Data</th>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <th>Output</th>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <td width="33%">
72db4a8f2c8f0f8edadfaa736288ed7dc2535d02Ryan Grove ```handlebars
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove \{{> header}}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <p>Mustaches are awesome!</p>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove \{{> footer}}
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <td width="33%">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove title: 'My Page About Mustaches'
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <td width="33%">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <h1>My Page About Mustaches</h1>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <p>Mustaches are awesome!</p>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove <p>Copyright (c) 2012 by Me.</p>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<h3>Compiling and Rendering Templates</h3>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveHandlebars 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveTo 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove// Compile a template into a reusable function.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grovevar template = Y.Handlebars.compile('My favorite food is \{{food}}.');
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveWhen you're ready to render the template, execute the function and pass in some data. You'll get back a rendered string.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove// Render a previously compiled template.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grovevar output = template({food: 'pie'});
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove// => "My favorite food is pie.";
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveYou can re-render the template at any time just by calling the function again. You can even pass in completely different data.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove// Re-render a previously compiled template.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Groveoutput = template({food: 'cheesecake'});
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove// => "My favorite food is cheesecake."
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveIf 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>.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove// Compile and render a template in a single step.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Groveoutput = Y.Handlebars.render('My favorite food is \{{food}}.', {food: 'pie'});
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove// => "My favorite food is pie."
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<h3>Precompiling Templates</h3>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveSince 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveThe 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<h5>On the Server</h5>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveTo 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):
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove$ npm install yui
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveThis will install the `yui` npm module in the current directory and make it available to your application.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveNext, 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove// Load the YUI Handlebars module.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grovevar Handlebars = require('yui/handlebars').Handlebars;
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove// Precompile a template string (pass any string you like here).
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grovevar precompiled = Handlebars.precompile('My favorite food is \{{food}}.');
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveThe `precompiled` variable will contain a string of JavaScript code that looks something like this:
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grovefunction (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;}
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan GroveThe `precompile()` method differs from the `compile()` method in a couple of important ways:
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove<li><p>The `precompile()` method returns a string of JavaScript code that's meant to be parsed and executed later, whereas `compile()` returns a live JavaScript function.</p></li>
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove<li><p>The code returned by the `precompile()` method contains no references to any outside objects. Once it's evaluated, the resulting precompiled function must be passed to the <a href="{{apiDocs}}/classes/Handlebars.html#method_template">`Y.Handlebars.template()`</a> method, which will "revive" it and make the functionality of the current page's Handlebars class available to it.</p></li>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveYou 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveHere's a simple <a href="http://expressjs.com/">Express</a> app that precompiles a template on the server and renders it on the client:
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grovevar Handlebars = require('yui/handlebars').Handlebars,
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove app = require('express').createServer(),
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove precompiled = Handlebars.precompile('My favorite food is \{{food}}.');
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Groveapp.get('/', function (req, res) {
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove '<html><body>' +
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove '<script src="http://yui.yahooapis.com/{{{yuiVersion}}}/build/yui/yui-min.js"></script>' +
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove '<script>' +
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove 'YUI().use("handlebars-base", "node", function (Y) {' +
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove 'var template = Y.Handlebars.template(' + precompiled + ');' +
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove 'Y.one("body").append(template({food: "pie"}));' +
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove '</script>' +
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove '</body></html>'
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveTo 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>.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<h5>On the Command Line</h5>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveThe 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveFirst, 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveNext, 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.
80a99dc7007d0bd18ea3c780d71fad66946b0f06Ryan Grove$ npm install -g handlebars
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveNow you can run the `handlebars` executable to precompile a template into JavaScript code.
80a99dc7007d0bd18ea3c780d71fad66946b0f06Ryan Grove$ handlebars my-template.handlebars -f precompiled-template.js
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveThis will compile a template to a JavaScript file which you can load on your page. You could render it like this:
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<!DOCTYPE html>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<meta charset="utf-8">
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<title>My Favorite Food</title>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<div id="content"></div>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<script src="http://yui.yahooapis.com/{{{yuiVersion}}}/build/yui/yui-min.js"></script>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveYUI().use('handlebars-base', 'get', 'node', function (Y) {
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove // Create a global Handlebars variable that points to Y.Handlebars. This is
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove // necessary for compatibility with precompiled templates generated by the
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove // original Handlebars project.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove // Load the precompiled template JS onto the page.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove Y.Get.js('precompiled-template.js', function (err) {
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove Y.error('Template failed to load: ' + err);
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove // Render the template and insert its output into the page.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove var output = Y.Handlebars.templates['my-template']({food: 'pie'});
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove Y.one('#content').append(output);
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove<h2>Differences From Original Handlebars</h2>
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveThe 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`.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan GroveYUI Handlebars differs from the original Handlebars in the following minor ways:
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove 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.
11fd1815d64adbb9ceca3073cf4a1dc6620cb74cRyan Grove 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. This ensures consistency with other parts of the library.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove 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!).
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove 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.
303c0f451e22f69b62c43a65066c6c20d27fcd63Ryan Grove YUI Handlebars appends a "-yui" suffix to the `Y.Handlebars.VERSION` property.