Poor man's JavaScript Behaviours
JavaScript behaviours are roughly defined as an event handler that is set once, then handled by elements that are created on the fly later on.
For example, if I have a list of links referencing images which are loaded inline, adding an removing the links from this list would not require me to re-hook the event handler.
There is a jQuery plugin called LiveQuery which can handle this for you, and does so by caching the event handler you set and hooking in to the .append(), .after(), etc, methods to reattach the cached event handler to the newly created elements.
The poor man's behaviours takes a different approach.
The technique is really very simple, and if you've been writing JavaScript you may have already made use of it in some form. It doesn't use a timer, and makes use of event bubbling.
In our example, our HTML would look like this:
<ul id="imageLinks">
<li><a href="/images/1.jpg">Image 1</a></li>
<li><a href="/images/2.jpg">Image 2</a></li>
<li><a href="/images/3.jpg">Image 3</a></li>
</ul>
Clicking on a link would load the image dynamically, but for our example, we'll just log the image url.
The JavaScript event handling is set on the ul element instead of the anchor elements.
// addEvent function for IE + Firefox
var addEvent = (function () {
return document.body.addEventListener ? function (e, ev, fn) {
e.addEventListener(ev, fn, false);
} : function () {
e.attachEvent("on" + ev, fn);
};
})();
addEvent(document.getElementById('imageLinks'), 'click', function (event) {
// only proceed if the user click on an anchor
var el = event.target;
if (el.nodeName == 'A') {
// this is our real event code - which we can read values
// from the 'el' variable, including .href, .rel, etc. to
// handle specific like code
console.log(el.href);
return false; // cancel click event
}
});
As you can see the core of the event handling is within the if (el.nodeName == 'A') (note the casing on the nodeName must be capitalised). If you need to match a class name, you can do it here too.
Taking it Further
This can be converted to a jQuery plugin, that supports more complicated selector matches, again without any timeouts.
It's limitation over LiveQuery, is that it's restricted to a subset of elements, i.e. a group of links that match X selector within a UL.
(function ($) {
$.fn.behaviour = function (selector, fn) {
return this.click(function (ev) {
var el = ev.target;
if ($(el).is(selector)) {
return fn.call(el);
}
});
};
})(jQuery);
$(function () {
$('#imageLinks').behaviour('a', function () {
console.log('Clicked link: ' + this.href);
return false;
});
});
Here's a working demonstration of poor man's behaviours
You should follow me on Twitter here I'll tweet about JavaScript, HTML 5 and other such gems (amongst usual tweet-splurges)
Just a simple correction. Live Query doesn't rely on timers to monitor the DOM. Instead it uses hooks.
@Brandon - cheers for the correction. I've updated the blog post.
Nice! I've been looking for a bubbling-events-example written in jQuery. Very handy indeed.
Hi Remy
What you are showing, already exists as a plugin, actually twice.
Intercept:http://code.google.com/p/jqueryintercept
Delegate:http://dev.jquery.com/browser/trunk/plugins/delegate/jquery.delegate.js
Listen is similar but not exactly the same.
Listen:http://flesler.blogspot.com/2007/10/jquerylisten.html
Cheers
@Ariel, I'd agree with you on the delegate plugin (the first link doesn't work), but the plugin I wrote above is just supposed to be very simple.
Really, I posted to demonstrate the simplistic behaviour approach, and I show this using "vanilla JS" first.
Personally, if I were to use behaviours extensively on an app, I'd be more inclined to use Brandon's liveQuery plugin.
Hi Remy
I meant my post as informative, not attacking, really
The link was meant to be:
http://plugins.jquery.com/project/Intercept
Anyway, that plugin it's pretty outdated. Note that LiveQuery belong to Brandon, not Jorn.
And I agree LiveQuery is the easiest to implement. But event delegation also has its advantages on large apps.
@Ariel - no problem!
Thanks for the correction too - I'll update that now.
[...] Poor man’s JavaScript Behaviours [...]
There's an error in the IE half of the addEvent function. It should look like this:
var addEvent = (function () {
return document.body.addEventListener ? function (e, ev, fn) {
e.addEventListener(ev, fn, false);
} : function (e, ev, fn) { // this line was incorrect
e.attachEvent("on" + ev, fn);
};
})();
Thanks for making this code available!