5 Comments

Introducing ICanHandlebarz.js – ICanHaz.js, meet Handlebars.js

I am currently working on a project that’s using ICanHaz.js and Mustache.js as a templating solution.  While I appreciate the logicless-templating paradigm that Mustache is built around, I quickly found that there were some problems in our application that just couldn’t be solved cleanly with the existing Mustache implementation:

  • No scoping mechanism
  • Undefined whitespace behavior

An hour or two poking around on google revealed Handlebars.js, which attempts to solve the major problems we encountered. While Handlebars.js has some extra features that I feel deviate slightly from the concept of “Logicless” Templating (see Advanced Usage after the jump), you can get by just fine without them.

During my preliminary testing, I found that I missed the ease of having ICanHaz.js wrapping all my templates, so I melded Handlebars.js into the nice ICanHaz.js framework and created ICanHandlebarz.js.

Basic Usage

ICanHandlebarz.js is mostly directly interchangeable with ICanHaz, with changes necessary only where Handlebars’ behavior differs from Mustache’s.

To add a Handlebars template to a webpage, you just need to include it in your HTML. ICanHandlebarz.js scans the document on load for anything with script type text/html and an id tag, compiles it, and attaches a function to trigger it to the global object “ich”.

<script id="villainprofile" type="text/html">
    <div class="villain-profile">
        <div class="name">Name: {{realName}}</div>
        <div class="alias">Alias: {{alias}}</div>
        <div class="powers">Powers: {{superPowers}}</div>
    </div>
</script>

You can then actually make use of this template anywhere in your javascript, just by calling ich.villainprofile. For example, using jQuery, we can create a villain within an existing DOM element.

var villain = {
  realName: "Ronald McDonald",
  alias: "Mickey D",
  powers: "The fry frazzler"
}
$('#villain').html(ich.villainprofile(villain));

This will stuff the templated data into the #villain element of the DOM.

Paths

To fix the scoping issues present in Mustache, Handlebars introduces a concept of paths. Paths look and function much like relative filesystem paths. For example, if you need to print a link that has both a parent and child ID in it, you could use something like this.

<script id="accomplices" type="text/html">
    <div class="accomplice-list">Known Accomplices:
    {{#accomplices}}
        <div class="accomplice">
            <a href="/api/{{../id}}/accomplice/{{id}}" class="accomplice-link">
                <div class="accomplice-alias">Alias: {{alias}}</div>
                <div class="accomplice-description">Description: {{description}}</div>
            </a>
        </div>
    {{/accomplices}}
    </div>
</script>

Advanced Usage

ICanHandlebarz.js supports most Handlebars.js features, including Partials and Helpers. The use of partials is exactly the same as it is for ICanHaz.js, so I’ll concentrate on Helpers, which are new in Handlebars.js.

Helpers allow you to register a function that will process data before it is displayed. This is the part of Handlebars that really deviates from the “Logicless” ideas of Mustache, but it can be extremely handy. As an example, ASP.net DateTimes serialize to a string format that uses unix time. This is all well and good, but very rarely would I care to directly inject a unix time into an HTML page. This is where helpers come in.

We’ll use a helper called “dateformat” to format an ASP.net date that we receive from some API. To keep consistency with ICH Partials and Templates, the helper function lives in the HTML document and is bound as a Handlebars helper at page load. Because of this, the function arguments live as a comma-separated string in a meta argument called “data-args”, and the function body lives within script tags.

<script id="lastModified" type="text/html">
    <div class="modified-date">This page last modified on {{{dateformat aspDate}}}</div>
</script>

<script id="dateformat" class="helper" data-args="aspDate" type="text/html">
//<![CDATA[ // Optional if there are no &, <, or > in your javascript.
      aspDateString = aspDate.toString()
      var dateObject = new Date(parseInt(aspDateString.substr(6)));
      return (dateObject.getMonth()+1) + '/' + dateObject.getDay() + '/' + dateObject.getFullYear();
//]]>
</script>

More Info

ICanHandlebarz.js is capable of much more. Check out the Handlebars.js and ICanHaz.js websites for a good intro to both of the primary components, and you’ll have a pretty good foundation for starting out with ICanHandlebarz. ICanHandlebarz should support all the features of Handlebars, although block helpers have not been extensively tested.

Check out the project on Github