Block helpers make it possible to define custom iterators and other functionality that can invoke the passed block with a new context.
<div class="entry"> <h1>{{title}}</h1> <div class="body"> {{#noop}}{{body}}{{/noop}} </div> </div>
noop
helper (short for "no operation") will receive an options hash.
This options hash contains a function (options.fn
)
that behaves like a normal compiled Handlebars template.
Specifically, the function will take a context and return a
String.
Handlebars.registerHelper('noop', function(options) { return options.fn(this); });
this
, so you can invoke the block with
this
to evaluate the block in the current context.
noop
on the context object would be referenced using:
{{./noop}}
<div class="entry"> <h1>{{title}}</h1> <div class="body"> {{#bold}}{{body}}{{/bold}} </div> </div>
bold
helper will add markup to make its text bold.
As before, the function will take a context as input and return a String.
Handlebars.registerHelper('bold', function(options) { return new Handlebars.SafeString( '<div class="mybold">' + options.fn(this) + '</div>'); });
with
helper
with
helper demonstrates how to pass a parameter to your helper.
When a helper is called with a parameter, it is invoked
with whatever context the template passed in.
<div class="entry"> <h1>{{title}}</h1> {{#with story}} <div class="intro">{{{intro}}}</div> <div class="body">{{{body}}}</div> {{/with}} </div>
{ title: "First Post", story: { intro: "Before the jump", body: "After the jump" } }
noop
helper. Helpers can take
parameters, and parameters are evaluated just like expressions
used directly inside {{mustache}}
blocks.
Handlebars.registerHelper('with', function(context, options) { return options.fn(context); });
each
helper works.
<div class="entry"> <h1>{{title}}</h1> {{#with story}} <div class="intro">{{{intro}}}</div> <div class="body">{{{body}}}</div> {{/with}} </div> <div class="comments"> {{#each comments}} <div class="comment"> <h2>{{subject}}</h2> {{{body}}} </div> {{/each}} </div>
each
once for each element in the comments Array.
Handlebars.registerHelper('each', function(context, options) { var ret = ""; for(var i=0, j=context.length; i<j; i++) { ret = ret + options.fn(context[i]); } return ret; });
<ul>
wrapper, and wraps each resulting element
in an <li>
.
{{#list nav}} <a href="{{url}}">{{title}}</a> {{/list}}
{ nav: [ { url: "http://www.yehudakatz.com", title: "Katz Got Your Tongue" }, { url: "http://www.sproutcore.com/block", title: "SproutCore Blog" }, ] }
each
helper.
Handlebars.registerHelper('list', function(context, options) { var ret = "<ul>"; for(var i=0, j=context.length; i<j; i++) { ret = ret + "<li>" + options.fn(context[i]) + "</li>"; } return ret + "</ul>"; });
Handlebars.registerHelper('list', function(context, options) { return "<ul>" + context.map(function(item) { return "<li>" + options.fn(item) + "</li>"; }).join("\n") + "</ul>"; });
if
and
unless
control structures are implemented as regular
Handlebars helpers.
{{#if isActive}} <img src="star.gif" alt="Active"> {{/if}}
Handlebars.registerHelper('if', function(conditional, options) { if(conditional) { return options.fn(this); } });
else
functionality
to block helpers.
{{#if isActive}} <img src="star.gif" alt="Active"> {{else}} <img src="cry.gif" alt="Inactive"> {{/if}}
else
fragment
as options.inverse
. You do not need to check for the
existence of the else
fragment: Handlebars will detect
it automatically and register a "noop" function.
Handlebars.registerHelper('if', function(conditional, options) { if(conditional) { return options.fn(this); } else { return options.inverse(this); } });
{{#if isActive}} <img src="star.gif" alt="Active"> {{else if isInactive}} <img src="cry.gif" alt="Inactive"> {{/if}}
unless
helper could be used in the else portion as with any
other helper. When the helper values are different, the closing mustache
should match the opening helper name.
list
helper
and make it possible for us to add any number of optional attributes
to the <ul>
element we will create.
{{#list nav id="nav-bar" class="top"}} <a href="{{url}}">{{title}}</a> {{/list}}
options.hash
. This
makes it easier to accept a variable number of parameters, while
also accepting an optional Hash. If the template provides no hash
arguments, Handlebars will automatically pass an empty object
({}
), so you don't need to check for the existence of
hash arguments.
Handlebars.registerHelper('list', function(context, options) { var attrs = Em.keys(options.hash).map(function(key) { return key + '="' + options.hash[key] + '"'; }).join(" "); return "<ul " + attrs + ">" + context.map(function(item) { return "<li>" + options.fn(item) + "</li>"; }).join("\n") + "</ul>"; });
Block helpers can also inject private variables into their child templates. This can be useful to add extra information that is not in the original context data.
For example, when iterating over a list, you may provide the current index as a private variable.
{{#list array}} {{@index}}. {{title}} {{/list}}
Handlebars.registerHelper('list', function(context, options) { var out = "<ul>", data; if (options.data) { data = Handlebars.createFrame(options.data); } for (var i=0; i<context.length; i++) { if (data) { data.index = i; } out += "<li>" + options.fn(context[i], { data: data }) + "</li>"; } out += "</ul>"; return out; });
data
option are
available in all descendent scopes.
index
field of the parent iterator, @../index
may be used.
data
field is defined prior to attempting to
interact with an existing data object. The private variable behavior is condtionally
compiled and some templates might not create this field.
{{#each users as |user userId|}} Id: {{userId}} Name: {{user.name}} {{/each}}
user
will have the same value as the current context and userId
will have the index value for the iteration.
{{#each users as |user userId|}} {{#each user.book as |book bookId|}} User Id: {{userId}} Book Id: {{bookId}} {{/each}} {{/each}}
blockParams
options field.
Handlebars.registerHelper('block-params', function() { var args = [], options = arguments[arguments.length - 1]; for (var i = 0; i < arguments.length - 1; i++) { args.push(arguments[i]); } return options.fn(this, {data: options.data, blockParams: args}); });
{{#block-params 1 2 3 as |foo bar baz|}} {{foo}} {{bar}} {{baz}} {{/block-params}}
1 2 3
on render.
options.fn.blockParams
field, which is an integer count. This value represents the number of block parameters that could be referenced by the child template. Parameters beyond this cound will never be referenced and can safely be omitted by the helper if desired. This is optional and any additional parameters passed to the template will be silently ignored.
{{{{raw-helper}}}} {{bar}} {{{{/raw-helper}}}}
raw-helper
without interpreting the content.
Handlebars.registerHelper('raw-helper', function(options) { return options.fn(); });
{{bar}}