Thursday, January 23, 2014

Handlebars Helpers vs String Utilities

The Handlebars client-side template system let's the developer register new template helpers. In effect, this extends the template syntax, adding to the short list of available helpers. The decision to include as few helpers as possible in the package was an intentional one - there's no sense including a lot of stuff that nobody uses. Especially when it's easy enough to make your own using registerHelper(). For this reason, only the bare essentials such as if and each are available out of the box. But is there an alternative approach to formatting your template data?

There's another tactic I've used in the past, I just call them simple string utilities for lack of a better term. Essentially, the code that renders the Handlebars template is responsible for formatting each template value before it's passed into the template context. There are upsides and downsides to either approach, and it really depends on your specific scenario when deciding which approach is best. Let's start by looking at the templates themselves.

<template id="template-helper">
    <p>The date is {{#date now}}{{/date}}</p>
</template>

This template fragment is displaying a date value. It's formatting the date by passing the now variable to a date template helper we've implemented. Now let's take a look at what the template syntax looks like without the use of a helper.

<template id="template-tostring">
    <p>The date is {{now}}</p>
</template>

The difference is subtle, but that latter has less-verbose syntax. Obviously simplified syntax is preferable, but on the other hand, the template author has to rely on the string version of the helper being formatted correctly. So the trade-off here is simplified syntax for loss of formatting control. Now let's take a look at how the helper and the string utility are implemented. Here's the helper.

Handlebars.registerHelper( "date", function( date ) {
    return date.toLocaleString();    
});

Note that this is called once, before any templates are rendered. The helper is then globally available — in any template. Now, here's what the string utility looks like.

function DateString( date ) {
    this.toString = function() {
        return date.toLocaleString();    
    };
};

This utility lazily evaluates the same thing as the Handlebars helper. The advantage to this approach is that your string formatting isn't tightly-coupled with the Handlebars machinery. The downside is that you need to call this utility everywhere the template is rendered. But, the same argument can be made about the templates themselves with the helper approach — you have to remember to use the helper everywhere you want dates formatted accordingly. So, you have choices in terms of where to allocate responsibilities in your template rendering architecture. Do you want the templates themselves to be solely responsible for formatting data? Or do you value being able to control the data formatting elsewhere in the code, while having a simplified template syntax? There's also room for some in-between combination of both approaches.