Cleaning your markup with dojo.behavior

CSS separates our formatting from our content. But we’re still left with onclick="..." attributes sprinkled throughout our otherwise pristine markup - not exactly “unobtrusive Javascript”. Dojo.behavior comes to the rescue, providing a nice separation between our content and the code associated with it.

Traditionally we use inline event handlers:

<ul>
<li onclick="if(confirm('Are you sure?')) {this.parentNode.removeChild(this);}"><img src="/images/100100.png" /></li>
<li onclick="if(confirm('Are you sure?')) {this.parentNode.removeChild(this);}"><img src="/images/100101.png" /></li>
</ul>

Dojo.behavior allows us to use clean markup:

<ul id="imageList">
<li><img src="/images/100100.png" /></li>
<li><img src="/images/100101.png" /></li>
</ul>

Combined with a single, concise piece of Javascript to add the functionality:

dojo.behavior.add({
    '#imageList li': {
        onclick: function(evt) {
            if (confirm('Are you sure?')) {
                this.parentNode.removeChild(this);
            }
        }
    }
});

Ben Nolan came up with the Behaviour Javascript library in based on recommendations by PPK and Simon Willison about unobtrusive Javascript. Dojo.behavior brings Ben’s library to Dojo, with the power of dojo.query() (and US spelling). The behaviour code is in Dojo Core, so we just need to do dojo.require("dojo.behavior") to get started.

At their simplest, behaviours consist of a CSS selector and some code. The selector can use classes, IDs, node types or anything else supported by dojo.query(). On the code side, there are a few different configurations of behaviours, which are outlined below.

Running code for each node:

dojo.behavior.add({
    '.foo' : {
        found: function(node) {
            // do something with each node found
        }
    },
 
    // shortcut for found
    '.foo2' : function(node) {
        // do something with the node
    }
});

Connecting to DOM events (using dojo.connect() underneath):

dojo.behavior.add({
    '#my li': {
        onclick: function(evt) {
            alert('click!');
        },
        onmouseover: function(evt) {
            alert('mouseover!');
        }
    }
});

Publishing topics (using dojo.publish() underneath):

dojo.behavior.add({
    '.topic1': {
        found: '/foo/t1/found',
        onclick: '/foo/t1/click'
    },
 
    // shortcut for found
    '.topic2': '/foo/t2/found'
});

Dojo.behavior consists of two functions - add() and apply(). You can register as many behaviours as you need to with add(), then call apply() to take all the registered behaviours and apply them to the nodes. When the page is loaded apply() is automatically called once for you, so normally you just need one or more add() calls.

Next, we can pull all our behaviours into a separate Javascript file. Once we’ve done this we have clear separation between the content (HTML markup), presentation (in a CSS file), and behaviour (in a JS file). Which makes the designers and the coders much happier.

Tags: