Stephen M. McKamey, 2007-02-03

JsonML - Binding Behaviors to DOM Elements

Progressive Enhancement

As the Ajax-savvy Web advances, best practices continue to emerge with emphasis on creating advanced UI without leaving the older generation of browsers behind. One such paradym shift is occuring from the traditional Web design strategy of "Graceful Degradation" to the concept of "Progressive Enhancement". Essentially the idea is to bootstrap an interface by building it up where advanced features are support, rather than allowing a controlled breakdown in sub-optimal environments. This concept goes by many other catchy buzz-words such as "Hijax" and "Unobtrusive JavaScript".

The Strategy: Unobtrusive JavaScript

The implementation strategy is an elegant one. Build out an interface in semantically correct XHTML, use externally linked CSS to control the display, attach to elements JavaScript behaviors defined in externally linked JavaScript files. This way the markup is free of inline JavaScript and styles, creating more of a Model-View-Controller separation. This however isn't a discussion of all the reasons to use this technique, as others have already sufficiently covered it.

Adding behaviors in JsonML

As previously discussed, JsonML is a unique solution to the problem of dynamically building out markup in an Ajax-style web application. It solves a number of problems which exist in the Ajax space. What may not be clear though is how to use JsonML to aid in the progressive enhancement strategy. Luckily these concepts are built into JsonML.

The reference implementation for a JsonML builder takes as a parameter a callback method. As the DOM elements are being constructed, JsonML passes each one into this method before actually adding it to the document. This allows the page to remove, transform or bind behaviors to the element. For example,

/*void*/ function bindBehaviors(/*element*/ elem) { if (elem.className.indexOf("Remove-Me") >= 0) { // this will remove from resulting DOM tree return undefined; } if (elem.tagName.toLowerCase() === "a" && elem.className.indexOf("External-Link") >= 0) { // this is the equivalent of target="_blank" elem.onclick = function(evt) { window.open(elem.href); return false; }; } if (elem.className.indexOf("Fancy-Widgit") >= 0) { // bind to a custom component FancyWidgit.bindDOM(elem); } return elem; } var myUI = JsonML.toHTML(myUITemplate, bindBehaviors);

The possibilities of this are enormous. This particular example shows behavior and action based upon special CSS classes and tag names. Also note that these behaviors can be composed together. For instance, if an element had more than one CSS classes applied to it then both would be bound. Notice that by returning undefined the element can be removed from the resulting document entirely. Also note that since this is called on each element as it is built the behaviors aren't limited to the top element but can be applied anywhere in the JsonML tree.

Show Me!

For an example of this in action, see the JsonML Samples page. These examples demonstrate when special bindings or "effects" are applied or when the markup is used as is.

For a detailed explaination of the JsonML syntax and sample code, check out: http://jsonml.org