Saturday, October 22, 2011

Underscore.js Templates in Backbone.js

‹prev | My Chain | next›

Up tonight, I would like to take some time to explore using Underscore.js templates in my Backbone.js application. At this point, I have a fairly involved calendar application mostly based on Backbone:


Most of the generated HTML in that application is not from underscore templates. The month view is dynamic, but I mostly built that prior to switching to Backbone. Really, the only part that is done entirely in the usual Backbone way is the individual appointment views. For those, I have a simple underscore template:
<script type="text/template" id="calendar-appointment-template">
  <span class="appointment" title="<%= description %>">
      <%= title %>
      <span class="delete">X</span>
  </span>
</script>
I really dislike the ERB style of embedding executable or interpolated bits of code inside angle brackets. It is hard for my brain to process and can even fool syntax highlighting in Emacs on occasion. So first up, I am going to follow along with the underscore documentation suggestion of switching to a saner mustache style that surrounds variables to be interpolated with double curly braces:
<script type="text/template" id="calendar-appointment-template">
  <span class="appointment" title="{{ description }}">
      {{title}}
      <span class="delete">X</span>
  </span>
</script>
Ahhhh... much better. Of course to actually make that work, I need to teach underscore to use mustache rather than silly old ERB. The default in underscore comes from:
  // By default, Underscore uses ERB-style template delimiters, change the
  // following template settings to use alternative delimiters.
  _.templateSettings = {
    evaluate    : /<%([\s\S]+?)%>/g,
    interpolate : /<%=([\s\S]+?)%>/g
  };
To override, I add the following to my page:
<script>
$(function() {
  _.templateSettings = {
    interpolate : /\{\{([\s\S]+?)\}\}/g
  };
});
</script>
Since I want this to apply everywhere, that does not have to be inside my backbone code. There are some benefits to global variables.

After replacing a couple of other small ERB templates, I would like to tackle something a bit more dynamic—namely the month calendar view:
<script type="text/template" id="calendar-template">
<h1>
  {{ title }}
  <span class="year-and-month">{{ date }}</span>
</h1>
<table>
  <thead>
    <tr>
      <th>S</th>
      <th>M</th>
      <th>T</th>
      <th>W</th>
      <th>T</th>
      <th>F</th>
      <th>S</th>
    </tr>
  </thead>
  <tbody>
  {[ _([0,1,2,3,4,5]).each(function(i) { ]}
  <tr class="week{{ i }}">
    <td class="sunday"></td>
    <td class="monday"></td>
    <td class="tuesday"></td>
    <td class="wednesday"></td>
    <td class="thursday"></td>
    <td class="friday"></td>
    <td class="saturday"></td>
  </tr>
  {[ }); ]}
  </tbody>
</table>
</script>
That is going to require looping over 6 weeks to build up the month calendar view. For that, I add an "evaluate" mapping in underscore's template settings:
    _.templateSettings = {
      evaluate : /\{\[([\s\S]+?)\]\}/g,
      interpolate : /\{\{([\s\S]+?)\}\}/g
    };
I am not wed to the {[ ... ]} format for evaluatable mustache-y code, but it does work.

With a decent understanding of how to implement dynamic underscore views, I call it a night here. I will pick back up tomorrow converting my non-Backbone calendar view into a legitimate Backbone view using this template.


Day #182

5 comments:

  1. Great introduction to underscore templates in BackBone JS !

    I will use Mustache templating now too :)

    ReplyDelete
  2. sorry, just wanted to clarify. you have both the evaluate and the interpolate template settings as the same thing -doesnt that pose any problems? ie the compiler not being able to differentiate between those two things?

    ReplyDelete
    Replies
    1. They are different. The interpolate option is double curly braces. Evaluate is curly brace + square bracket. Later I ended up dropping the evaluate entirely. Felt good :)

      Delete
  3. Thanks!

    It helped me get around the collision between erb <%= %> and underscore <%= %> being the same. :)

    ReplyDelete