apike.ca

Easy Templates with jQuery and Underscore

By mbystedt on Nov 9, 2012, 7:27:56 PM

jQuery and Underscore can be used together is to create clear and fast loading templates.

I'm going to use underscore's native templates in this post but this could be expanded to any template engine. First, we need to load the template data. One way to do this is to embed the template in a hidden div. For small templates or templates that need to load quickly this is probably sufficient. I'll just assume the template is a separate document that needs to be loaded.

Loading a file (jQuery.Deferred)

jQuery provides a deferred object (and interface) that is quite flexible. It allows you to hook onto something and wait for it to finish. Once it finishes (or if it's already finished), your code gets a callback. If this sounds like how ajax is done, you're right. jQuery's ajax calls implement this interface as an alternative (and enhancement) to just passing in a callback when you make a Ajax call.

webRoot: "server/path/",
templatePromises: {},
loadTemplateAsync: function(tmpId) {var promise = this.templatePromises[tmpId] || jQuery.Deferred();    
    if (this.templatePromises[tmpId]) {
        return promise;
    }
    this.templatePromises[tmpId] = promise;
 
    jQuery.get(this.webRoot + tmpId, function(data) {
     promise.resolve(_.template(data));
    });
    return promise;
},
Object snippet

The above code will return either a new or cached jQuery deferred object. Once the asynchronous call to get the template returns the data, it creates the template object from the data and calls resolve() on the deferred object. At this point, the code waiting for the template will proceed.

Waiting for your template

So, how do you use the deferred object returned by loadTemplateAsync()? Look at this snippet:

var tempLoadPromise = TemplateUsingObj.loadTemplateAsync("template/demo.html"); 
 
tempLoadPromise.done(function(template) {
	console.log(template({templateVar: "Hello, World!"}));
});

The underscore template is:

<%=templateVar%>

Great! So, this will load template on demand and log the result. As templates often are required after loading data, a good way to handle this is to make the call to loadTemplateAsync() before the ajax call and put the tempLoadPromise.done() in the data handler. That way, the data and template are requested simultaneously. Example:

var tempLoadPromise = TemplateUsingObj.loadTemplateAsync("template/demo.html"); 
 
jQuery.get("something", function(data) {
	tempLoadPromise.done(function(template) {
		console.log(template({templateVar: data}));
	});
});

For more information: