Thursday, August 7, 2008

JSRepeater

The javascript repeater microsite is here.

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:

  1. Memory
    1. 2 GB
    2. 3 GB
    3. 4 GB
  2. Hard Drives
    1. 250 GB
    2. 500 GB
    3. 500+ GB
  3. Graphics
    1. Integrated
    2. 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.

Sunday, August 3, 2008

Gadget Paper Cart

The Gadget Paper Cart is based on a template from Free Website Templates.

Using the CSS Body Snatching technique that I mentioned in my previous post I have added functionality to this template to give it the feel of a regular shopping cart.

If all you see is a CSS template you have to imagine how it would work in real life. Adding a bit of javascript gives you the chance to test drive the template in action. You can now get a feel for the user friendliness of the design itself.

You can see the template in action, and, if you want to have a play with the design yourself, download the source files.

Thursday, July 17, 2008

CSS Body Snatching

Yes, CSS is the best way to make sure all your <p> tags use the same font but ...

Have you ever thought of using CSS to control the flow of an application?

... with Body Class Switching, CSS can dictate not only how an application appears, but also how it functions.


Let’s use the example of an application with lots of user interaction; a shopping cart.

[1] [2] [3] [4]
  1. Category selection on the left, visitor selects category ...
  2. List of matching products, visitor selects product ...
  3. Full details displayed, visitor select [Add] ...
  4. My Cart displayed.

In an AJAX application it would normally be javascript that changes the layout as the visitor moves from [1] to [4].
If, instead of making assumptions about layout, javascript simply set the class of the body tag then CSS would be able to take over control from there.

Let's try that flow again

[1] -> [2] Visitor clicks a category and Javascript sets the body class
<body class='categoryselected'>
CSS can now take over and decide to display the product thumbnails
.categoryselected #thumbnailcontainer { display:block; }

[2] -> [3] The visitor clicks on a product and javascript says:
<body class='productselected'>
CSS responds with:
.productselected #productdetailcontainer { display:block; }

[3] -> [4] The visitor clicks on ‘Add to Cart’ and javascript says:
<body class='addedtocart'>
CSS replies:
.addedtocart #cartcontainer { display:block; }

What has happened is that CSS has taken control of the visual flow application.

Why do it?

Control   If the javascript is created being someone other than the designer then the designer is in control of what are essentially design decisions.

Maintainability   If the layout of the application changes then you don't have to plough through javascript trying to find out where to mirror the changes.

Portability   The same javascript library and server side code can be used to create two apparently different applications simply because they use a different stylesheet.

User friendly   You could give your users the choice of how they want to see the application, some might want everything on the screen at the same time in a control panel kind of scenario while other might be more comfortable with basic uncluttered screens.

Philosophical   Layout is a design decision and hard coding it into javascript blurs the separation between design and functionality.

An Example

Tuesday, July 15, 2008

Simple javascript repeater

Assume you want to add content to a page after it has loaded such as JSON data retrieved from the server e.g.:
var data = [{Name: 'Google', URL: 'http://www.google.com'},
{Name: 'Yahoo', URL: 'http://www.yahoo.com'},
{Name: 'LiveSearch', URL: 'http://search.live.com/'}];
This content could possibly be displayed as
<ul>
<li>Google [http://www.google.com]</li>
<li>Yahoo [http://www.yahoo.com]</li>
<li>LiveSearch [http://search.live.com/]</li>
</ul>
or perhaps
<p><a href='http://www.google.com'>Google</a></p>
<p><a href='http://www.yahoo.com'>Yahoo</a></p>
<p><a href='http://search.live.com/'>LiveSearch</a></p>
and you don't want to have to deal with that issue in the javascript function. Firstly, create an HTML template of what the contents would look like when displayed. In the template you will have to indicate the bits that would be substituted by the actual data received. In the tradition of many great javascript libraries we'll use the ${} notation where ${Name} indicates that you want the 'Name' property of the data coming in to be placed in that location.
<p> <a href='${URL}'>${Name}</a> </p>
Now that we have a template we need a javascript function that can populate it, here's one
function ParseTemplate(aryData, strTemplate) { var result = ""; for(var i = 0; i < data.length; i++){ var obj = aryData[i]; result += strTemplate.replace( /\$\{([^}]*)\}/g, function(match, group1) { return obj[group1]; } ); } return result; }
Now, whenever new data is loaded you simply need to tell the function what template you want to use and where to put the result. Here is a full code listing to try out: