Organized Selector Chaos with dojo.behavior

By  on  

One of the most underrated parts of writing good JavaScript code is writing *maintainable* code:  readable, modular, and clean.  Just because you use a JavaScript framework doesn't mean your code is maintainable.  Quick the contrary could be true -- some frameworks make JavaScript uglier.

Because of all the DOM node traversal that's involved with modern day JavaScript techniques, class usage and element event modification can quickly become spaghetti code.  Luckily dojo.behavior exists.  This Dojo class allows you to handle event querying and functionality assignment in a very uniform, clean manner.

Element Usage without Behavior:  query and forEach

The typical element collection and functionality assignment is done with dojo.query and dojo.forEach:

/* style updates */
dojo.query('a.someClass').forEach(function(item) {
	item.addClass('someOtherClass');
})

/* events */
dojo.query('a.someClass').forEach(function(item) {
	dojo.connect(item,'onclick',function() {
		console.log('clicked!');
	});
});

This code is by no means ugly, but it can quickly become a mess.  The other drawback to using this method is that there's no clean way to "enable" and disable these behaviors.  Once they're set, you need another code block to remove the behaviors.  Enter dojo.behavior.

Organization:  dojo.behavior!

dojo.behavior provides a solid, functional, and readable structure of handling selector-to-functionality assignments.  A quick format overview:

/* require the class */	
dojo.require('dojo.behavior');
	
/* super basic usage */
dojo.behavior.add({
	'a.someClass': function(node) { //assumes "found"
		console.log('Found a node:  ',node);
	}
});
dojo.behavior.apply();

/* multiple selectors */
dojo.behavior.add({
	'#someNode': {
		onclick: function(e) {
			e.preventDefault(); // stop the default event handler
			console.log('clicked! ', e.target);
		}
	},
	'div': {
		found: function(node) {
			console.log('Found a node:  ',node);
		},
		onclick: function(e) {
			console.log('this DIV was clicked! ', e.target);
		}
	}
});
dojo.behavior.apply();

dojo.behavior.apply...applies...the behaviors we've set.  Simple, effective, clean.

Widget Creation with dojo.behavior

Widget creation is an even better opportunity to use dojo.behavior:

dojo.behavior.add({
	'select': function(node) {
		//create this type of widget for all select elements
		new dijit.form.FilteringSelect({/* options */,node});
	},
	'input[type=text]': {
		found: function(node) {
			new dijit.form.TextBox({},node);
		},
		onfocus: function(e) {
			console.log('got focus!');
		}
	}
});
dojo.behavior.apply();

Event Assignement with dojo.behavior

Event assignment also works with dojo.behavior:

dojo.behavior.add({
	'a.disableClick': {
		onchange: function(e) {
			e.preventDefault();
		}
	}
});
dojo.behavior.apply();

As does topic subscribing:

dojo.behavior.add({
    '#someUL > li': '/found/li'
});
dojo.subscribe('/found/li', function(msg){
    console.log('message: ', msg);
});
dojo.behavior.apply();

Behave!

Though dojo.behavior doesn't save much code, it definitely makes code more readable and thus, more portable.

Recent Features

  • By
    Create a CSS Flipping Animation

    CSS animations are a lot of fun; the beauty of them is that through many simple properties, you can create anything from an elegant fade in to a WTF-Pixar-would-be-proud effect. One CSS effect somewhere in between is the CSS flip effect, whereby there's...

  • By
    Responsive and Infinitely Scalable JS Animations

    Back in late 2012 it was not easy to find open source projects using requestAnimationFrame() - this is the hook that allows Javascript code to synchronize with a web browser's native paint loop. Animations using this method can run at 60 fps and deliver fantastic...

Incredible Demos

  • By
    Use Elements as Background Images with -moz-element

    We all know that each browser vendor takes the liberty of implementing their own CSS and JavaScript features, and I'm thankful for that. Mozilla and WebKit have come out with some interesting proprietary CSS properties, and since we all know that cementing standards...

  • By
    Create a Context Menu with Dojo and Dijit

    Context menus, used in the right type of web application, can be invaluable.  They provide shortcut methods to different functionality within the application and, with just a right click, they are readily available.  Dojo's Dijit frameworks provides an easy way to create stylish, flexible context...

Discussion

  1. This blog post made me take a closer look at dojo.behavior – http://whatsthepointeh.blogspot.com/2010/09/dojoconnect-vs-dojobehavior.html

  2. Is this basically a way to prevent using dojo.query() in a way that is executed immediately whilst also providing a level of control over the commands?

  3. Paul Lysak

    Hi.
    I wonder if dojo.behavior can work well with declaratively created dijits. Say, for connecting handlers to menu items if this menu was created using “parseOnLoad: true” option.
    Thanks.

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!