It's all very well having JSON data coming from the server, the problem lies in displaying this data in a page. I used to write reams of javascript to append nodes to the DOM but I was looking for something a little more declarative so that each time I wanted to put another piece of data on a page I didn't have to write yet another hardcoded function.
I tried DOJO's repeater (dojox.iterator) but there were a few things such as nested repeaters which it didn't do, I had a look around at some of the other libraries available but none felt quite right, so I decided to write my own javascript repeater.
I Googled the term 'JSRepeater' and nothing came up so that's what I'll call it.
When the page is loaded the repeater will scan the page for any element which has the attribute template='true'. It will make a copy of that elements contents to serve as a template.
When you bind data to that template the repeater it will replace any markers with data from the source data and then place the result in the original template element for each item of data to which it was bound.
A few examples probably makes this clearer, first we need some JSON data to work with.
var Categories = [{"Name" : "Memory", "Subcategories" : [{"Name" : "2 GB"},{"Name" : "3GB"},{"Name" : "4GB"}]},
{"Name" : "Hard Drives", "Subcategories" : [{"Name" : "250 GB"},{"Name" : "500 GB"},{"Name" : "500+ GB"}]}
{"Name" : "Graphics", "Subcategories" : [{"Name" : "Integrated"},{"Name" : "Dedicated"}]}]
Basic Binding
In order to display all the categories in an unordered list we could use the following template
<ul id="CategoryList" template="true">
<li>${Name}</li>
</ul>
In the onload event of the page we would insert the following two lines:
// Initialise the jsRepeater
var rpt = new jsRepeater();
// Bind the data to the template
rpt.bindTemplate('CategoryList', Categories);
which would result in:
- Memory
- Hard Drives
- Graphics
When we bound the template to the data the JSRepeater looped through each category and wrote out the template we created substituting ${Name} for the Name of the category.
Binding nested data
The previous example only displayed categories but categories have subcategories as well and if we want to display the whole hierarchy in one fould swoop we let the repeater know this by using the context tag e.g.
<ol id='CategoryList2' template='true'>
<li>${Name}
<ol><li context='Subcategories'>${Name}</li></ol>
</li>
</ol>
Once again the repeater parses the template for each category but when it gets to an element with the context tag it evaluates that against the current category and treats that <li> as a separate inner template and parses it for each subcategory in the current category. Inside that template ${Name} no longer refers to the category but the subcategory.
The result is this:
- Memory
- 2 GB
- 3 GB
- 4 GB
- Hard Drives
- 250 GB
- 500 GB
- 500+ GB
- Graphics
- Integrated
- Dedicated
There is more ...
The jsRepeater does a lot more than this but a blog is not the place to go into all the details. To that end I have put up a microsite at jsRepeater, please check it out and see what other functionality jsRepeater has to offer.