Tag Archives: Underscore

On Templating in Backbone

I recently saw a post on Hacker News about adding custom extensions to Handlebars which allow you to call methods on the data that is passed to your Handlebars template. Before I had a chance, someone astutely pointed out that Handlebars is designed for logicless view rendering, but that other templating solutions do offer the ability to include real logic in your templates.

This got me thinking, and I thought I’d share what has been my approach to templating in my own Backbone apps.

Handlebars – beautiful syntax & logic made difficult

Handlebars is designed to be semantically pleasing. It’s hard to beat in terms of syntax:

<h1>{{title}}</h1>
<ul>
  {{#each people}}
  <li>{{this}}</li>
  {{/each}}
</ul>

When it comes to logic though, you are limited to a few basic built-in helpers or are forced to add your own custom helpers. For instance, if you want to check for whether a description attribute is truthy, you can do this:

    {{#if description}}
       <span>{{description}}</span>
    {{/if}}

But if you are looking to check whether an attribute matches a given value, you are out of luck.

Does not work

    {{#if age >= 21}}
        <h1>Drink up!</h1>
    {{/if}}

This is a reasonable thing to wish to do, but to do this in Handlebars would require you to write your own custom extension, like so:

Helper method
    Handlebars.registerHelper('isLegal', function(val, options) {
       if ( val >= 21 ) {
          return options.fn();    
       } else {
          return options.inverse();
       }
    });
Template
    {{#if isLegal}}
       <h1>Drink up!</h1>
    {{else}}
       <h1>Bummer</h1>
    {{/if}}

There is something to be said for forcing you to work hard to implement custom logic in your templates, but we programmers are pragmatic and sometimes you just want something done fast. In these cases, I like to fall back on a much uglier, more powerful templating solution: _.template()

Underscore – ugly syntax & logic made easy

Underscore templates won’t win any awards for elegance. While they may appeal to some Java jockeys coming from JSPs, for most of us it’s a no-brainer which syntax is easier to use.

    <h1><%= title %></h1>
    <ul>
      <% for (var i = 0; i < people.length; i++ ) { %>
      <li><%= people[i] %></li>
      <% } %>
    </ul>

That being, said, logic is easy and you can put as much of it as you like in your Underscore templates!

    <% if ( age >= 21 ) { %>
        <h1>Drink up!</h1>
    <% } %>

I choose… both!

With Backbone, I think people feel like they have to choose between the two ways of templating, each with its own advantages and drawbacks. But I think this is really a false choice – each excels in its own way and with Backbone it’s easy to choose both!

What I have found to be best is a Handlebars-first, Underscore-if-needed approach. You can’t beat Handlebars for syntax, and your project ought to be structured in such a way that your templates don’t require much logic anyway. But in those cases where you really do need something more powerful, there is no harm done in falling back on Underscore. In fact, since Backbone itself depends on Underscore already, it’s already right there waiting for you to use!

Here’s an example of 2 views, one which renders with Handlebars, and one with Underscore:

HandlebarsView
 var HandlebarsView = Backbone.View.extend({
        template: _.template(handlebarsTemplate);
        model: new Backbone.Model({
            title: "Famous Authors",
            authors: ["Hemingway","Hawthorne","Orwell"]
        }),
        
        render: function() {
            this.$el.html(this.template(this.model.toJSON()))
        }
    });
Handlebars Template
    <h1>{{title}}</h1>
    <ul>
      {{#each people}}
      <li>{{this}}</li>
      {{/each}}
    </ul>
UnderscoreView
var UnderscoreView = Backbone.View.extend({
        template: Handlebars.compile(underscoreTemplate);
        model: new Backbone.Model({
            age: 23,
            legalMessage:"Drink up!"
        }),
        
        render: function() {
            this.$el.html(this.template(this.model.toJSON()))
        }
    });
Underscore Template
    <!--Underscore Template-->
    <% if ( age >= 21 ) { %>
        <h1>Drink up!</h1>
    <% } %>

Here we see how little effort is required to swap out your templating engine (something of a contrived example, I know). This can be done on a View-by-View basis and IMHO offers the best of both worlds. I’d love to hear your thoughts, so leave a comment or hit me up on Twitter.