Wednesday, January 24, 2007

A Pattern for Building Web Widgets

One of my favorite parts of being a Web Developer is implementing cool dynamic Javascript widgets. I've recently had to build a tab control and an 'accordion menu'. I spent most of today in Pair Programming mode, building a combo box which uses asynchronous calls to the server to fetch its data.

I admit, I was reinventing the wheel, but I really had no choice. I couldn't find any widgets that were readily customizable or worked just the way I liked.

In the end, the html snippet (I'm calling it a template tag) to create my widget looked something like this:

<input class="picker" data_source="/db/collection" fields="field_1" />

MochiKit makes this sort of thing very easy and clean. The code does a search of input tags with a class of 'picker' (getElementsByTagAndClassName), does some DOM creation magic, then finally uses the swapDOM call to drop the completed widget onto the page. I pass arguments into the widget constructor via the custom (non XHTML compliant!) attributes I stick in template tag.

I attach all the attributes and methods I need to the containing DOM element, so that the application code can use the getElement function to reference the widget, and then call its functions, change attributes etc. Basically, I ended up with a DIV element decorated with methods like update_list, get_selected, and a onselect stub method which is designed to be overridden.

In the end, my remoting combo box code was built over 6 hours with 87 lines of javascript and 50 lines of CSS. The backend code which supplied the data in JSON format was written within the TurboGears framework, and took 20 minutes and < 50 lines of code.

This is the basic pattern I now use for dynamically creating widgets using MochiKit.


if(typeof(widget) == 'undefined') {
widget = {}
widget.init = function() {
var setup = function(template) {
/*
create the widget, assign methods
and attributes to the widget
*/
swapDOM(template, new_widget)
}
map(setup, getElementsByTagAndClassName('input', 'widget'))
}
}

addLoadEvent(widget.init)


It gives me neat, easy to understand, self contained .js files for each widget, with MochiKit as the only dependency.

No comments:

Popular Posts