Creating your own custom Handlebars bounded if’s in Ember

Ember.js, JavaScript, Programming

Ember uses the Handlebars templating library to create views.
Ember ‘registers’ a whole bunch of Handlebars helpers to make creating templates easier, for instance the {{link}} helper to create links to different routes.

In the same way Ember registers / adds new helpers to Handlebars you can do the same, you could for instance create a helper that capitalizes a word:

The ‘registerBoundHelper’ creates a helper that reevaluates whenever the argument changes. So if the ‘name’ changes the helper is rerendered with the new name.

However in older versions of Ember it was not possible to add bounded block helpers to Handlebars.

A block helper is defined as:

“Block helpers make it possible to define custom iterators and other helpers that can invoke the passed block with a new context.”

Examples of block helpers are {{if}}, {{with}} and {{each}}. Bounded versions of these helpers mean that they get reevaluated / rendered when the condition changes.

So creating your own version of an if statement that updated when the condition changed was very difficult. Here’s a usecase and the story of why I needed to create my own custom bounded {{if}}, and how I eventually did it:

In an App that I made we had the following case: We wanted to display a rain meter, it shows the user how many millimeters precipitation fell on a day.
The rain meter works via radio waves, which can get scrambled, missed or otherwise interfered. If this is the case our server sends the value ‘null’
to the Ember application. If the server tells me the “mm” key is ‘null’ I want to display “No data” if it was anything other than “null” I want
to display that number. This was my first attempt:

On first glance this worked well, unless it was a clear day when rainmeter.mm was actually the value ‘0’ as in zero, then it would display no data. This is because {{if}} is only true when the value is not an empty array, zero, null, undefined or “”. I had to create my own {{if}} that handles
accepting the value 0 as truthy. My if should work as follows, everything is true except null and undefined:

This approach worked for the longest time, until I got reports that “No data” was visible whilst the rainfall.mm was not ‘null’. This puzzled me for the
longest time, until I realized that the condition only gets evaluated once. Meaning that if rainmeter.mm was ‘null’ once and then changed to 12.3 it would not recheck the {{if}}’s condition. Changing from 12.4 to 13.0 would still work because the condition would be true in both cases. I needed a way to write my custom {{if}} so that got reevaluated each time the condition might change.

For the longest time I could not find any way to fix this, but then ‘registerBoundHelper’ got released. It created a way to make bound helpers in Ember, still no bounded {{if}}’s but it was a nice place to start digging. It looks like this:

The last line looked very promising it calles this function called bind which creates a binding which reevaluates when the condition changes. Now all I need to do is change the function that determines the condition’s value. It is called ‘func’ so I changed it to:

Now it worked like a charm. The only thing was that the ‘bind’ function used to be private so I had to alter Ember itself so I could reach it. But in the new version of Ember ‘bind’ is visible through Ember.Handlebars.bind.

So that’s my story about creating custom Ember bounded {{if}}’s

I do however like to point out that my case ‘ifData’ was used many times throughout the app. I do not recommend creating custom bounded {{if}}’s when only needing it once or twice, in that case I would use computed properties instead, which is way more emberesque.

Here’s a Ember JS bin so you can play with it yourself, and where you can see al versions of the {{if}} side by side:

http://emberjs.jsbin.com/ebobilUS/10/edit

Leave a Reply

Your email address will not be published. Required fields are marked *


8 × four =

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">