Nesting Handlebars helpers into templates.

If you are building a lot of html templates using Handlebars then here is a walk through of slimming them down using Require.js, require handlebars plugin and Handlebars helper system.

A really good use case for this is building forms. Say you wanted to keep a common className and structure across all your app. You might start with a simple form like this one:

<form role="form">
  <fieldset>
    <div class="form-group">
      <label for="name" class="control-label">Name</label>
      <input class="form-control" type="text" id="name" />
    </div>
    <div class="form-group form-group--email">
      <label for="email" class="control-label">Email</label>
      <input class="form-control" type="email" id="email" />
    </div>
    <input type="submit" />
  </fieldset>
</form>

The first thing we could do would be to create reusable helpers which will build the label and input elements.

Cheeky little helpers

It’s great starting small as it allows you to be quite granular when using helpers within your templates. You can always build helpers which utilise other helpers.

Let’s build a simple label helper:

  define(function(require){
  
    // register our dependencies
    var Handlebars = require('handlebars');
    
    // create a label helper
    Handlebars.registerHelper(
      'input_label',
      // we'll make context be the text
      function(context, options){
        // we'll send in the id as an attribute
        id = options.hash.id;
        return '<label for="'+ id +'" class="control-label">'+ context +'</label>';
      }
    );
    
  });

Now after this simple helper and maybe a similar one for the input we can change the template to:

<form role="form">
<fieldset>
<div class="form-group">
{{{input_label 'Name' id='name'}}}
{{{input_text my_var id='name'}}}
</div>
<div class="form-group form-group--email">
{{{input_label 'Email' id='email'}}}
{{{input_email my_date id='email'}}}
</div>
<input type="submit" />
</fieldset>
</form>

Already it’s looking better and we’ve saved ourselves a lot of refactoring should we need to change class names or add another attribute to the input element across all email inputs.

Helping helpers

Now we could take this one step further by encapsulating both label and input in a helper saving us the need to repeat the id. Also it’s not too pretty having html embedded in the JavaScript so lets also use the power of Require.js and the Handlebars plugin to really simply use another template inside.

  define(function(require){
  
    // register our dependencies
    var Handlebars = require('handlebars');
    
    // template helpers
    var group_text = require('hbs!templates/group_text');
    
    // create previous helpers
    // ...
    
    // create a group helper
    Handlebars.registerHelper(
      'group_text',
      function(context, options){
        // create a simple link to the value
        // so we can just pass the options
        // as data
        options.value = context;
        return group_text(options);
      }
    );
    
    // create other group helpers
    // ...
    
  });

Then within our group_text.hbs file we can not only place the surrounding markup but we can also use the helpers we’ve created previously.

<div class="form-group">
{{{input_label hash.label id=hash.id}}}
{{{input_text value id=hash.id}}}
</div>

And let’s look at our resulting form template.

<form role="form">
<fieldset>
{{{group_text my_var label='Name' id='name'}}}
{{{group_email my_date label='Email' id='email}}}
<input type="submit" />
</fieldset>
</form>

Soooo much neater!! Much easier to maintain across all the forms within your app.

Work with me

Dave is a cohesive team member, widely popular with his colleagues and always inspiring quality, exploration and innovation. One of the true ‘greats’ we’ve had the pleasure to work with

I believe in community, in inspiration and creativity. I believe it's an inspired team and a laser focus on the user's experiece that will produce the best results. I want to help frontend teams live inspired, be productive and scale better.