Underscore.js Templates

After the post about why Underscore.js, I think it is best to follow up on one of the best parts of the library. Now, I haven’t had a chance to go through the new templating in jQuery, however what I have found with Underscore.js has allowed me to complete some very complicated tasks in my day to day work.

Lets take a look at the documentation for _.template and then we will dig into it a bit more:

template_.template(templateString, [context])
Compiles JavaScript templates into functions that can be evaluated for rendering. Useful for rendering complicated bits of HTML from JSON data sources. Template functions can both interpolate variables, using

<%= … %>, as well as execute arbitrary JavaScript code, with <% … %>. When you evaluate a template function, pass in a context object that has properties corresponding to the template’s free variables. If you’re writing a one-off, you can pass the context object as the second parameter to template in order to render immediately instead of returning a template function.


var compiled = _.template("hello: <%= name %>");

compiled({name : 'moe'});

=> "hello: moe"
var list = "<% _.each(people, function(name) { %>

<li><%= name %></li>

<% }); %>";


_.template(list, {people : ['moe', 'curly', 'larry']});

=> "

<li>moe</li>

<li>curly</li>

<li>larry</li>

"

Pasted from <http://documentcloud.github.com/underscore/>

So what can we do with this? Lets take a look at showing some employee data:

Standard Templating


var employeeList = [
{
name : "John smith",
position : "CEO",
pay : 1,
hours : 2020,
type : "USD"
},
{
name : "Jane Smith",
position : "CFO",
pay : 2,
hours : 2020,
type : "USD"
},
{
name : "Alex Smith",
position : "Lead Programmer",
pay : 500,
hours : 2020,
type : "EUR"
}
];
var template = "
<table cellspacing='0' cellpadding='0' border='1' id='employee'>
<tbody>
<tr>
<td>Name</td>
<td>Position</td>
<td>Pay</td>
<td>Hours</td>
<td>Type</td>
<td>Total Compensation</td>
</tr>
<% for (var index = 0; index < employeeList.length; index++){ %>
<% var employee = employeeList[index]; %>
<% var compensation = employee.hours * employee.pay; %>
<tr>
<td><%= employee.name %></td>
<td><%= employee.position %></td>
<td><%= employee.pay %></td>
<td><%= employee.hours %></td>
<td><%= employee.type %></td>
<td><%= compensation %></td>
</tr>
<% } %>
</tbody>
</table>
";
$(document).ready(function() {
var output = _.template(template, { employeeList : employeeList } );
$("#employeeContainer").html(output);
});



The corresponding output is below:



Now, if we were requesting the data from an Ajax call based on some parameters this would make it a bit more interesting, but you can get a feeling for how to take data and a view for that data and output something that actually makes sense.

So lets dig a bit more into the different tags, and why the is on each line.

  1. JavaScript does not handle multiple line strings (why, no idea but it would be really helpful to have multi line strings. Even if they used something like the perl EOF delimiter to figure out where the end of the string should be, but I digress). In order to have a multi-line string, we need to add the (backslash) to the end of each line to tell the JavaScript parser that there is more on the next line.
  2. Note that the string is started using the double quote “, which means we need to make sure anything in the string that is quoted is either in single quotes or escaped using the backslash. e.g. ”
  3. <% versus <%=
    1. So this is a bit more complicated, if you want to use straight Javascript and don’t want the output on the line we need to use <%. Also, if you use <% you MUST add a semi-colon ; at the end of the JavaScript line and then follow it with the %> to enclose the line of JS.
    2. <%= is the way we actually print out the variables to the template. With this tag, DO NOT put a semi-colon ; at the end of the line or the template will break.

Dynamic Templating With Includes

There is one more thing we should look at. Templating is nothing without includes, so how on earth do you create an include with this system. Well, we can use some other magic that would allow us to access template from other templates.

So lets modify the script a bit, and see what we can do.


var template2 = "
<table cellspacing='0' cellpadding='0' border='1' id='employee'>
<tbody>
<tr>
<td>Name</td>
<td>Position</td>
<td>Pay</td>
<td>Hours</td>
<td>Type</td>
<td>Total Compensation</td>
</tr>
<% for (var index = 0; index < employeeList.length; index++){ %>
<% var employee = employeeList[index]; %>
<% var compensation = employee.hours * employee.pay; %>
<tr>
<td><%= Label.getHTML({ name : employee.name }) %></td>
<td><%= employee.position %></td>
<td><%= employee.pay %></td>
<td><%= employee.hours %></td>
<td><%= employee.type %></td>
<td><%= compensation %></td>
</tr>
<% } %>
</tbody>
</table>
";
var Label = new function() {
var template = "<%= name %>";
this.getHTML = function(data) {
return _.template(template, data);
};
};
$(document).ready(function() {
var output = _.template(template2, { employeeList : employeeList } );
$("#employee2").html(output);
});

The corresponding output is below:



Overall with this method of templates and includes we can make very complex sites with a clear separation of data and views.

12 thoughts on “Underscore.js Templates

  1. google earth live

    Hello just thought i would tell you something.. This is twice now i’ve landed on your blog in the last 3 weeks hunting for completely unrelated things. Spooky or what?

    Reply
  2. momschips

    i was starting to imagine i would probably be the only gentleman who thought about this, at least currently i realize im not nutty :) i will make sure to look into some several other posts soon after i get some caffeine in me, take care :)

    Reply
  3. sklep internetowy

    Aw, this was a really quality post. In theory I’d like to write like this also – taking time and real effort to make a good article… but what can I say… I procrastinate alot and never seem to get anything done… Regards

    Reply
  4. Luis

    I’ve been looking for information about keyboard accessibility for content generated via underscore templates – and I havent found anything yet. I like your post here and wanted to shoot a template related question by you , and all.

    Basically, I have a site that generates tons of content this way but sadly, the generated content doesnt appear to have tab stops or put another way, one cannot interact with the content with just the keyboard (tab to focus, enter to click).

    Have you seen this in more generated markup? Is this avoidable (maybe Im doing something wrong) or just an accepted thing about using this pattern?

    Normally, I make a web app work without js 1st and then enhance it but for this project, that was impossible with time and budget constraints. If I could post links to my work, I would (wish I could).

    Still, Im hoping you may have some insight here. Any ideas about this?
    Thanks

    Reply
  5. Luis

    This is not my work (obviously?), but illustrates what I’m interested in resolving:

    http://www.flickr.com/photos/jonathansnook/5572801441/in/photostream/

    The red highlighted areas are elements that can be tabbed to via the keyboard, then activated/interacted with by pressing Enter. My prototype pages with the exact same markup was tab-able, but when I switched to generated content via underscore templates (Backbone views) the elements became ‘invisible’ to the keyboard despite having identical markup.

    I’m looking for a way to restore the tab-stops to generated content so that users can use the website via keyboards and not have to rely on mouse interaction.

    Thanks JS!

    Reply
  6. devang paliwal

    Nice detailed description. I am using underscore JS for templating and encountered complex use case for it.
    Underscore js templating is very similar to JSP aka java server pages. It took me no time to understand and use after reading your blog. Thanks.

    Reply
  7. Johne885

    I appreciate, cause I discovered just what I used to be looking for. You have ended my four day long hunt! God Bless you man. Have a nice day. Bye caeefefgeace

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>