A Better JavaScript Template Engine 08.25.08
Rizqi Ahmad from Germany has introduced a nice solution for client-side template based on JQuery. The Chain.js allows you to use any piece of HTML (or embedded HTML string) as template to display data dynamically.
In introductory post, he went through some common approach like server-side data binding, injecting preformatted HTML (into well-known DOM property innerHTML) and directly manipulating DOM, then explained why Chain.js is better way:
- Easy and compact (as it uses JQuery for manipulating DOM)
- Preserve event(s) on updates
- Allow dynamically add/remove data
To use the engine, you’ll need to download JQuery (better the latest version) and Chain.js then add script tags to load them.
<script src="path/to/jquery.js" language="javascript"> </script> <script src="path/to/chain.js" language="javascript"> </script>
Practical Example on Chain.js
Now, we’ll create a practical example that allows user select a programming language and display recommended reading books accordantly. This is almost similar to another example I created for PURE library.
First, build a template table to display book list:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <table class="books"> <thead> <tr> <th>Title</th> <th>Publisher</th> <th>Price</th> </tr> </thead> <tbody id="book_table_body"> <tr class="item"> <td class="title"> </td> <td class="publisher"> </td> <td class="price"> </td> </tr> </tbody> </table> |
Second, get data (books) from server based on selected language selected via Ajax using JQuery function $.getJSON().
1 2 3 4 5 | $.getJSON('json.php', 'lang=' + $('#langList').val(), function(books){ ........ } ); |
We’ll have a list of books in JSON format that looks like:
[{title: "Sams Teach Yourself Java 6 in 21 Days", publisher: "Sams", price: 29.69}, {title: "Java In A Nutshell", publisher: "O'Reilly", price: 29.67}, {title: "Effective Java", publisher: "Sun", price: 28.79}]
Then just tell Chain to parse the books and add them to the table body:
$('#book_table_body').items(books).chain();
All JavaScript codes to get it work are as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 | function render(){ $.getJSON('json.php', 'lang=' + $('#langList').val(), function(books){ $('#book_table_body') .items('destroy') /* clear previous items */ .items(books) /* parse items */ .chain(); /* chain them */ }); } $(document).ready(function(){ $('#langList').change(render); // handle change event of drop-down list setTimeout(render, 100); // call render function on load }); |
See this example online: Example 1. Select each language to see the book list below changed.
Add/Remove & Sort Items
Chain.js supports adding, removing and sorting items with minimal efforts. To visualize the functionality, we’ll create some INPUT fields to add new data to the book table.
1 2 3 4 5 6 | <div class="add-data"> Title: <input id="input_title" type="text" width="10" /> Publisher: <input id="input_publisher" type="text" width="10" /> Price: <input id="input_price" type="text" width="10" /> <input type="button" value="Add" onclick="addData()" /> </div> |
Then, define addData() function that responses to “onclick” event of Add botton :
1 2 3 4 5 6 7 | function addData(){ var data = [{title: $('#input_title').val(), publisher: $('#input_publisher').val(), price: $('#input_price').val()}]; $('#book_table_body').items('add', data); } |
To support removing a row by double clicking on it, we’ll bind the event on chain method:
1 2 3 4 5 6 7 8 | $('#book_table_body') .items('destroy') /* clear previous items */ .items(books) /* parse items */ .chain(function(){ /* bind event */ this.dblclick(function(){ $(this).item('remove'); // remove item }); }); |
The last functionality we wish at the moment is to sort items. First, we have to create some links on table header:
1 2 3 4 5 6 7 8 9 10 | <table class="books"> <thead> <tr> <th><a href="javascript:void(0)" onclick="sortBy('title')">Title</a></th> <th><a href="javascript:void(0)" onclick="sortBy('publisher')">Publisher</a></th> <th><a href="javascript:void(0)" onclick="sortBy('price')">Price</a></th> </tr> </thead> … </table> |
And define sortBy() function to handle sorting items by column, not complicated as you may think:
1 2 3 | function sortBy(col){ $('#book_table_body').items('sort', col, {toggle:true}); } |
That’s all. Please see online example: Example 2 and feel free to add items, to remove one by clicking on the row and sort them (ascendant or descendant).
Advanced Custom Data Binding
The last example is to explore a bit advanced functionality which I find very useful in practice: custom data binding. As you can see in the above examples, data binding are made by default: Chain.js matches data field with element class name and render text into it. In practice, it’s very often that we want to format or bind data to sub-elements instead.
For example, now we want to:
- Format “Price” to fixed 2 decimal, add a dollar sign before number and make it align at right.
- Add another column called “Order” that link to order page (say http://amazon.com/…)
The template table must be modified to add a new column (Order) that contains a link by default:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <table class="books"> <thead> <tr> <th>Title</th> <th>Publisher</th> <th>Price</th> <th>Order</th> </tr> </thead> <tbody id="book_table_body"> <tr class="item"> <td class="title"></td> <td class="publisher"></td> <td class="price3"></td> <td class="order"> <a class="order-link" href="#"></a> </td> </tr> </tbody> </table> |
On chain method, we’ll define a directive to tell Chain how to bind data:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | $('#book_table_body') .items('destroy') /* clear previous items */ .items(books) /* parse items */ .chain( /* Custom data binding */ { '.price3': { style: 'text-align: right', content: function(data, el){ return '$' + data.price.toFixed(2); } }, '.order .order-link': { style: 'color: red;', href: '{orderLink}', target: '_blank', content: 'Order Now!' } } ); |
Only problem I found is the custom data binding does not override default one so that I have to rename class of price row to “price3” or Chain won’t parse the directive (but simply use “raw” price number as Example 1). Hope Rizqi Ahmad will fix that in the next version?
Online example is here.
Conclusion
Chain is very nice and comprehensive solution I can find among many others, thanks to compact syntax and simplified DOM manipulate method by JQuery — Just write less and do more with HTML template! Please download all source codes of above examples at the following link.
Update: Revised examples based on Chain.js v0.2 can be found here.

















August 27th, 2008 at 4:23 pm
Excellent post, I have been meaning to learn more about JQuery, here is a good place to start!
August 28th, 2008 at 3:57 am
Javascript Templates are very topical because, thanks to AJAX, we find ourselves with lots of JavaScript objects that somehow have to make it into the markup.
I have also been looking around for templating solutions. I want to have to write as little javascript as possible and wanted a solution where all the heavy lifting is done in the HTML. Let’s face it, it’s easier to change HTML than to write javascript to create HTML.
None of the templates I have found do all the things I wanted e.g. more than one alternating template, nested templates, specifying which part of the object you want to bind to, and importantly; being able to bind recursively without having to specify a subtemplate for each level down.
So I wrote one. I have made it available as an opensource jquery plugin.
Perhaps you might find it useful as well.
http://jsrepeater.devprog.com/
August 28th, 2008 at 3:57 am
Thanks for the post!
but I think, there are still some missunderstanding about the way chain.js should be used ;). If I release the v0.2, would you please update this article? (Only if you want).
@Shawn
This is not about templating, but about managing data efficiently and more importantly scaling! You can write a simple code first, and extending it as it is required. For example, chain.js is so extensible that you can extend it to provide useful interaction service as can be seen here: http://github.com/raid-ox/interaction.js/wikis/demos
Actually I wrote similar library two years ago, called zparse: http://code.riiv.net/zparse/ . But using string based templating and innerHTML, makes your code too limited, not enough flexibility.
Of course jsrepeater is very efficient and easy, but as your code grow and grow, jsrepeater can’t provide the flexibility that is required.
August 28th, 2008 at 3:57 am
@Shawn: Being able to bind recursively looks useful though I don’t really like template tags in HTML — just disable JavaScript in your browser and you’ll see ${…} tags left on the page.
September 15th, 2008 at 2:10 pm
@Jimmy: Thanks for having a look at the jsRepeater library
I understand the initial dislike for ${} tags in the HTML. They are after all not HTML. However, they do serve the function of being easier to use. An alternation tag %{odd:even} replaces in a few characters what would normally take many lines of javascript to accomplish.
I built this library in order to make it easy to use. Changing layout in HTML is much easier than changing it in javascript. If there is anything I can offer in their defence it would be that ${} markup is declarative in the same way that is declarative whereas javascript if functional.
@Risqi - Thanks as well for having a look at the jsRepeater library. I had a look at the library you mentioned and appreciate the similarities although I did baulk at explicit ‘for’ loops in HTML markup. I think of HTML as being declerative whereas a ‘for’ loop in HTML did seem to be a bit of a mix of metaphors.
You mentioned that your project, while being eay to use in the beginning, suffered from scaleability issues. Do you have any examples of these, prehaps a particular example in which templates using innerHTML could not rise to the challenge? I would appreciate it if you could post it so that we could all benefit from the lessons you learned. (I tried to open the demos at http://github.com/raid-ox/interaction.js/wikis/demos but IE7 died on all the example pages with the error ‘Operation Aborted’, damn IE!, unfortunately we can’t ignore it).
Keep up the good work!
September 16th, 2008 at 10:03 am
Thanks for the hint! It is actually caused by IE not handling document correctly. So I moved the script to $(document).ready.
I am actually don’t call chain.js a templating engine, it is rather a data binding service.
by the way you’re asking about more advanced example, so I created it here:
http://code.riiv.net/demos/tree/
best regard, Rizqi
September 18th, 2008 at 6:15 am
(Note: I posted this on JustTalkAboutWeb as I don’t know which blog you will be maintaining)
Hi Jimmy,
We have just released a new version of PURE, including new features such as :
Auto-rendering: a new PURE method takes your HTML and your JSON data and merges them automatically. The class attribute is used to map the HTML and the data.
Recursive Template Call
The changes are quite important.
We took back your example and changed it to fit with the new release.
The code source can be seen below and as you will see, it is really easier :
http://friendpaste.com/FSBbhtb5
I have a zip file for you with the example if you contact me directly.