Ember has a number of built-in Handlebars
helpers, like
{{view}}, {{#if}}, or {{action}}.
You can also define your own helpers to DRY up your templates. I’ll explain how to do this, and then how to deal with bindings.
Unbound Helpers
Let’s say you want to write an i18n helper (which you really shouldn’t, since
there is ember-i18n), so that {{t
helloWorld}} produces “Hello World!”.
1 2 3 4 5 | |
Let’s dissect this: registerHelper takes two arguments: the name of the
helper, and the helper function. The helper function takes the argument
(i18nKey) and an options hash. It returns a string, which will be safely
HTML-escaped by Ember.
To have your helper take optional arguments (e.g. {{t greeting World}}),
CoffeeScript splats are very useful:
1 2 | |
Helper options can be accessed through options.hash, e.g.
options.hash.lang for {{t greeting lang="en"}}.
Bound Helpers
Update: There is now support for bound Handlebars helpers in Ember master (46469837).
If you find yourself writing get in a helper function without some sort of
binding, something is going wrong. Using get assumes that the data you are
get’ting is available before the helper is run. Even if it happens to work now,
relying on this ordering invites a slew of issues – exactly the kind that
Ember was designed to prevent. Instead, you need bound helpers.
Unfortunately, there is no canonical way to create bound helpers yet (#1274). If you try to set up observers manually, you are in for a lot of complexity.
Luckily, there is a cool trick: Instantiate a view from the helper function
by deferring to the {{view}} helper.
Here is a generic helper function that I use to create helpers that defer to views:
1 2 3 4 5 6 7 8 9 | |
For example, let’s implement a {{capitalize}} helper, so that if
{{name}} is “whizboo”, then {{capitalize name}} is “Whizboo”,
and it will stay up-to-date as the name changes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
This is in fact a really useful general-purpose technique for creating bound
helpers. You can even pass options (fooBinding="someProperty"), which will
be set on the view.
DRYing Further
If you write more helpers like the one above, you’ll find that many can be
expressed as a unary function of the content argument. I like to have a
helper function to DRY up these kinds of helpers:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
Now, for example, register a {{capitalize}} helper like this:
1 2 3 | |