Thursday, February 18, 2010

JS: Client side templating

I originally created this for an autocomplete widget I needed for a project ages ago; eventually it became too annoying to write all the code for the millions of conditions so I just used the YUI one instead, which is a pain in the arse to set up but works perfectly when you've done it.

Anyway, while looking around at existing solutions, they all seemed to have the problem that the markup was either fixed and styled with CSS, or generated in a callback. Neither of these solutions was ideal; the first results in a widget usable most of the time but very uncustomisable for more unusual uses, and the second is very designer unfriendly if you need to separate your coding and design teams.

So, my idea was to be able to write your HTML as normal, then mark an element as a template container. This template would contain databound variables. It would be removed from the DOM on page load, stored, then repeatedly generated for each item in a provided dataset.

Basically, it is inspired by the ASP.NET repeater control, .NET being my primary development environment.

I recently refactored the code to be more generally useful, and created a jQuery plugin wrapper that enables it to be used using the jQuery selectors and AJAX functionality.

It has uses beyond autocomplete, of course; any AJAXian updatable areas could use it.

Pros and cons are:

  • Keeps the template HTML in the same file as everything else; this can be a pro if the area is specific to a certain page or you are using a "master page" or "header / footer includes" style design, and a con if the template is to be used in several places. In that case you are probably better off with a server-side templating system to generate the HTML and dumping that in using the jQuery native functions.
  • Allows lightweight data transfer; instead of returning all of the HTML you can just return a JSON dataset.

The basic template code and the jQuery wrapper can be downloaded from the links below:

Usage:

First of all, you need a datasource, which will be an array of objects, for example:

[
 {id:1, name:'Alice'},
 {id:2, name:'Bob'},
 {id:3, name:'Carol'}
]

Then, you need to set up the template:

<ul id="testTemplate">
    <li class="@ItemClass">@Text</li>
</ul>

Note the SQL style variable placeholders. When the template is created with the ID of the <ul> element the <li> will be cleared. It is then reproduced for every item in the data array.

Note: EVERYTHING contained within the template element is treated as the data row, so you can have very complex repeating templates; as a very simple example you could have two list items for every data item should you want to. This is more useful for creating table based templates.

The actual call to populate the template looks like this:

// Call using local data and the simple unwrappered template code
var template = new HTemplates.Template('testTemplate');
template.populate(data);

// Call using the jQuery wrapper and an AJAX data source
$('#testTemplate').hTemplate();     
$('#testTemplate').hTemplate().populate(data);

You can download an example page plus an example JSON datasource from the links below:


Note: You will need the jQuery framework; it has been tested with 1.4. You will also need to change the script paths to match your setup.

The jQuery plugin is the first time I have looked at jQuery; I'm not 100% sure this is the best way to create a plugin; the hTemplate().populate() call looks odd to me. Also there is probably a better way of JSON parsing that is less fragile than my check-for-open-bracket-then-eval() method.

No comments:

Post a Comment