JavaScript Architecture: Underscore.js

12.19.2011

Underscore.js, like jQuery, is a toolbox of utilities. Check out the website for a list of functionality it provides, but I’ll split it into two parts:

Array/Object/Function manipulation

As we create software is seems like we come in contact with the same patterns over and over. Usually, we end up re-writing them over and over as well. Take an array of user objects, each with a username property. We need an array of all the usernames from all the objects. So, like many times before, we create a new array to populate, create a for loop, snag the object at the current index, grab the username and push it into the array.

To me, that’s boring. It’s mundane. Underscore makes it fun again. With Underscore, we just use pluck():

var usernames = _.pluck(users, 'username');

Ah…concise, fast, and boilerplate is gone. Want to find all objects within an array that pass a specific test? Use the filter() function. Just want a reference to the first one that passes the test? Use the find() function. Want to retrieve the union of two arrays, that is, retrieve a single array of all unique objects contained within multiple other arrays? Try the union() function. Merge properties of multiple objects into a single object? Use extend().

Once you grasp the power of Underscore you’ll find yourself being more productive with less code while having more fun. Some have called it the bowtie for jQuery’s tux. I concur.

Templating

The template() function is only one of the many listed for Underscore, but its purpose is very important.

Let’s say you’re building an app to manage your todo items. When the user creates a todo, it’s your job to create a todo row for the view. And maybe you want to allow them to select the row using a checkbox, delete the row, or edit the row in-line. Without using a templating engine, you might end up with something like this:

var todoTemplate = '' +
	'<div class="todo ' + (done ? 'done' : '') + '">' +
		'<div class="display">' +
			'<input class="check" type="checkbox" ' + (done ? 'checked="checked"' : '') + ' />' +
			'<div class="todo-text"></div>' +
			'<span class="todo-destroy"></span>' +
		'</div>' +
		'<div class="edit">' +
			'<input class="todo-input" type="text" value="" />' +
		'</div>' +
	'</div>';

This is troublesome. First, your html is likely buried somewhere inside your JavaScript code. This makes re-skinning an app much harder since you now have to track down all your html strings scattered throughout your logic. Second, concatenation takes time, is risky, and falls under the categories of mundane and frustrating. You have to deal with escaping and indentation. Your IDE probably isn’t going to color-code, code-hint, or auto-indent as well as it could if it were plain html. It’s easy to make a mistake and, since JavaScript is loosely typed, you might not find these mistakes until runtime. Also, if you dish your code off to HTML/CSS gurus, they now have to deal with these problems too.

Templating engines provide a better way of managing the situation. What if we added this at the bottom of our body tag instead:

<script type="text/template" id="item-template">
	<div class="todo <%= done ? 'done' : '' %>">
		<div class="display">
			<input class="check" type="checkbox" <%= done ? 'checked="checked"' : '' %> />
			<div class="todo-text"></div>
			<span class="todo-destroy"></span>
		</div>
		<div class="edit">
			<input class="todo-input" type="text" value="" />
		</div>
	</div>
</script>

There are a few things to note here.

  • The code is plain HTML except for those things that can be dynamic which are inline (<%=...%>).
  • The dynamic portions reference a variable called done. We’ll talk about that in a minute.
  • The code is wrapped in a script tag with a type of text/template meaning it won’t be interpreted as JavaScript (the default script type) by the browser. If it were, the browser would throw errors.
  • The script tag has an ID which allows us to later access its content.

At this point, the code inside the script tag is just innate text. The browser won’t try to execute it or anything of that nature. That’s where Underscore’s templating engine comes in. In our app JavaScript code, we can then take action like this:

var template = _.template($('#item-template').html());

The $('#item-template') code uses jQuery to reference the script element. Calling html() on the element then returns the inner html of the element–in this case the html that will represent a todo item. Here comes the underscore templating engine: _.template(). At this point a compiled template has been built. This allows us to now pass a context object into the compiled template to produce html we can then use for our todo item. This might look like so:

var todoHTML = template({done: true});

The portions of the template that depend on the done variable will be evaluated using the done property on the context object. The resulting todoHTML will be a string of html that looks like:

<div class="todo done">
	<div class="display">
		<input class="check" type="checkbox" checked="checked" />
		<div class="todo-text"></div>
		<span class="todo-destroy"></span>
	</div>
	<div class="edit">
		<input class="todo-input" type="text" value="" />
	</div>
</div>

You can then use jQuery to create an element out of the html. It’s as easy as

var element = $(todoHTML);

I should mention that a portion of this code is pulled from Backbone.js‘s Todos example.

Template management

You might rightfully be wondering how this is scalable if you start to have hundreds of templates in your html file or how you might be able to load them asynchronously only when needed. If you’ve asked yourself these things, congratulations! These are questions architects should be asking. We’ll talk about how to manage this in a later post.

Templating syntax

Underscore by default uses ERB-style template syntax (<%=...%>) which to me feels nasty and isn’t fun to type. You can change that to some other style like {{...}} as follows:

_.templateSettings = {
  interpolate : /\{\{(.+?)\}\}/g
};

Much better.

Other templating engines

The concept of a templating engine is not unique to Underscore or even JavaScript. There are many others in many languages. I feel the most notable ones in JavaScript outside of Underscore are Mustache.js and Handlebars.js. I use Underscore because it’s a top-notch templating engine, includes other Underscore functionality I use anyway, and it’s a dependency of Backbone.js which we’ll be discussing in a later post.

Where to use templates

After reading this, you may think templates are only appropriate for elements whose count is undetermined until runtime like our todo items. If so, may I suggest considering that everything should be a template?

What if you took everything in your body tag, broke it up into reasonably small templates, and left your body tag with nothing in it except for your templates? What if each DOM element and its contents produced from each small template were managed by a single JavaScript object? What kind of freedom would that bring your code? Could you move these components around more freely? Ship them over to be used in a different app? Would they be less coupled from one another and provide stronger APIs? Could you more appropriately add, remove, re-arrange, and manipulate these components rather than having a big fat HTML file written up front? Could you provide your users an all-around more dynamic experience? I hope you catch the vision. In upcoming posts we’ll see how this takes shape.

<< JavaScript Architecture: jQueryJavaScript Architecture: Backbone.js Events >>

Tags: , , , , , , ,


Comments

12.20.2011 / Dustin Woodard said:

I am a believer! I vow i will use templates from here on out. Awesome!

12.25.2011 / Aaron Hardy said:

Thanks Woodard. Let me know how they feel after you start using them.


Leave a Comment

Your email address is required but will not be published.




Comment