Event Delegation Made Easy
08 FEB
I’m having a lot of fun poking around jQuery at the moment and came up with a cool little thing that’s going into Low Pro for jQuery but is a nice stand-alone little snippet for implementing event delegation. Since the Christian and the guys at YUI started talking about it event delegation has gone from being something that I’d use occasionally to the way I do nearly all my event handling. If you aren’t familiar with the technique go and click that previous link and read Christian’s article now – it’s important.
In most instances I end up writing a lot of event handlers that look like this:
$('#thing').click(function(e) {
var target = $(e.target);
if (target.hasClass('quit') return doQuitStuff();
if (target.hasClass('edit') return doEditStuff();
// and so on...
});
Obviously, writing a lot of the same kind of code is a warning sign that something needs refactoring but I’ve never come up with a nice way to abstract this. But with a little bit of functional magic I’ve just found with something I really like. Here’s what I came up with:
jQuery.delegate = function(rules) {
return function(e) {
var target = $(e.target);
for (var selector in rules)
if (target.is(selector)) return rules[selector].apply(this, $.makeArray(arguments));
}
}
Using it is simple:
$('#thing').click($.delegate({
'.quit': function() { /* do quit stuff */ },
'.edit': function() { /* do edit stuff */ }
}));
The function simple runs through the rules checking if the element that fired the event belongs to that selector then calls the corresponding handler passing the original event object through. The great thing about it is that you can use it in Low Pro behavior classes:
DateSelector = $.klass({
onclick: $.delegate({
'.close': function() { this.close() },
'.day': function(e) { this.selectDate(e.target) }
}),
selectDate: function(dayElement) {
// code ...
},
close: function() {
// code ...
}
});
I’m not sure of the performance implications of using is() so heavily but some form of caching could be added if it was a problem. Still, it’s a really nice little bit of syntactic sugar that’s going into Low Pro for jQuery and I’ll be using it a lot.
UPDATE: I should have added that there’s a version of this in Low Pro for Prototype. In case you want to use it on its own:
Event.delegate = function(rules) {
return function(e) {
var element = $(e.element());
for (var selector in rules)
if (element.match(selector)) return rules[selector].apply(this, $A(arguments));
}
}
Meanwhile, you might want to take a look at the patch by Peter Michaux.
How To Use Low Pro For jQuery
03 FEB
Class-based OO
In order for Low Pro behavior classes to work with jQuery we need a class implementation. The one I’ve based this on is the version from Prototype originally based on Alex Arnell’s work. This is detailed in this article on the prototype site. The only difference is that instead of using Class.create you use $.klass:
Draggable = $.klass({
initialize: function(options) { },
onmousedown: function() {}
});
GhostedDraggable = $.klass(Draggable, {
onmousedown: function($super) {
// do extra stuff here then call original method...
$super();
}
});
Attaching the behavior class to elements
To attach the behavior class to some elements you can use the attach method:
$('div.product').attach(GhostedDraggable, { anOption: thing });
attach creates a new instance of the given behavior class for each element in the collection and
attaches them to these elements. Any subsequent arguments are passed to the class’s initialize function.
A few magic things happen here. First, this.element in the
behavior instance is set to a dollared version of the element it’s attached to. Secondly, every
method beginning with on (eg. onclick, onsubmit etc) gets bound as an event handler on the attached
element. However, in the event handler functions themselves, this points to the behavior instance
rather than the element so you can call it’s other methods. You can obviously get to the element
by using this.element if you need to though.
And for the bonus round…
So, that’s about all there is to it. One added bonus is that if you are using livequery then Low Pro will automatically use it to attach any new behaviors after the DOM is changed without you needing to worry about it.
Here’s a super simple example behavior that simply adds and removes a CSS class name when it is hovered over. It’s about as bare bones as you can get while showing off most of the features:
Hover = $.klass({
initialize: function(hoverClass) {
this.hoverClass = hoverClass;
},
onmouseover: function() {
this.element.addClass(this.hoverClass);
},
onmouseout: function() {
this.element.removeClass(this.hoverClass);
}
});
jQuery(function($) {
$('span.name').attach(Hover, 'myClassName');
});
For more information about how you might use behavior classes take a look at this article. ANother good point of reference is the built-in Remote.Link and Remote.Form behaviors that are built in to Low Pro. Take a look at the source Also a Low Pro site is on its way shortly. As I use it more myself I’ll post more real examples but you can post any questions to the Low Pro list.
Low Pro For jQuery?
31 JAN
The one big reason was that, while jQuery was super simple and concise when working on smaller projects, it offered no help in structuring larger applications. All you get in jQuery, aside from Ajax methods and a handful of utilities, is the ability to select nodes then doing something with them. On the other hand Prototype is much rounder in scope. It generally plumps out JavaScript as a language adding lots of useful methods to built-ins, a host of functional programming tools and recently a full Class-based OO system with inheritance and the whole shebang which has formed the back bone of Low Pro’s behavior classes.
Low Pro’s behavior classes have become my favourite solution to the problem of structuring complex Ajax applications in a simple and maintainable way. Even hugely complex applications can be separated up into a number of groups of elements with attached behaviors. These behaviors maintain their own state, respond to events and can also expose there own public methods. They are linked to an element but the element doesn’t know about them which eliminates the need for expandos on elements and also most of the reasons for having element references in closures which is good for keeping memory usage at bay. For instance, a click on a TabBar instance can call the loadContent method of a ContentPanel. The result is more than a set of widgets, its a way of splitting up huge complicated interfaces into a collection of small, loosely joined parts each simple in its own right and totally responsible for its part of the interface. This approach becomes incredibly useful when you introduce server-side requests and responses into the mix but that’s a whole other article.
In jQuery land this kind of effect can be achieved via plugins. You’ll find a ton of widgets in the repository that have this kind of UI:
$('#example4').draggable({ helper: 'clone', revert: true });
The plugin architecture is one of jQuery’s many strong points but this kind of approach has a couple of disadvantages. Firstly, the plugin is created within a closure which means usually if you want to change the behavior of the plugin you literally need to pop open the source and change it. The second and related disadvantage is that because of the difficulty in changing plugins they tend to have a whole raft of options to allow you to configure how it works. The problem with this is that individual widgets can end up pretty monolithic. Wouldn’t it be be better if you could just take the basic draggable behavior and just augment it to your liking?
Well, in Low Pro behaviors are classes so we can do this by simply subclassing another behavior and overriding or adding what we need. For example, we can create GhostedDraggable as a subclass of Draggable. No need to hack any existing code at all. As well as having the power and convenience of jQuery’s DOM manipulation we can have a simple and powerful way to structure larger, more complex applications. I can have my jQuery cake and eat it.
So, I’ve started experimenting with Low Pro for jQuery. Here’s a preview:
Hover = $.klass({
initialize: function(hoverClass) {
this.hoverClass = hoverClass;
},
onmouseover: function() {
this.element.addClass(this.hoverClass);
},
onmouseout: function() {
this.element.removeClass(this.hoverClass);
}
});
$('div.products').attach(Hover);
If you want to leave feeedback or abuse jump on the Low Pro list. Do you think it has a place in the jQuery landscape? How do you currently structure complex applications in jQuery?
UPDATE: Thanks to Chris of Err The Blog Low Pro JQ is rocking on GitHub. Fork away.
Low Pro 0.5: Now Compatible With Prototype 1.6
12 DEC
Today I tagged Low Pro 0.5 for release which now works with Prototype 1.6. There are a number of things about this release that are worth mentioning aside from the compatibility. Firstly, it’s gotten a little smaller as Prototype core now includes most of the functionality Low Pro used to add (DOM Ready support, inserting using DOM nodes and a lot more). It’s also got a couple of new features so here’s a rundown:
- Event.onReady delegates to the new dom:loaded event: Except that as before if functions are added after the DOM is loaded they fire immediately.
- DOMBuilder now delegates to Prototype’s new Element: Now difference in usage here though, just less code.
- Low Pro’s DOM methods are now gone: Prototype core does everything you should need now.
- Behavior.create() works just like the new Class.create(): Yes, you can now create behavior classes that inherit from other behaviors (or indeed any other class). See the Prototype’s site for more information.
- New core behaviors: The Remote and Observed behaviors are now included in the core so you can now turn normal links and forms into Ajaxy links and forms even more easily.
- Event.addBehavior.reassignAfterAjax is now false by default: Normally, if you are relying on this behavior it’s much more efficient to move to a solution using event delegation. However, if you do want your behaviors reassigned to new content after Ajax calls then go ahead and set it back to true again. Another solution is to manually call Event.addBehavior.reload();
So that’s about it. As you can see, it’s getting smaller as Prototype fills the gaps and graduating into more of a pure behavior framework. I’d be interested in adding more core behaviors for other common tasks as well as possibly getting together some kind of behavior library. I know I’m building up a fair few and I’d love to see what everyone else is doing (in fact I’ve already seen some great stuff) so suggestions are more than welcome…as are bug reports and patches. For both of these and general assistance try the Google Group.
Grab the new version and have a play.
Low Pro Archive 
- Event Delegation Made Easy 08 FEB
- How To Use Low Pro For jQuery 03 FEB
- Low Pro For jQuery? 31 JAN
- Low Pro 0.5: Now Compatible With Prototype 1.6 12 DEC
- Custom Attributes And Class Names 07 OCT
- Low Pro Behaviours 101: Part 2 18 JUL
- Low Pro Behaviours 101 17 JUL
- The State (And Future) Of The UJS Plugin 16 JUN
- Low Pro 0.4 Released 16 APR
- Low Pro: Unobtrusive Scripting For Prototype 03 SEP


