Event Delegation with JavaScript


Event delegation involves attaching event handler to parent DOM element. Reason is simple: when an event is triggered on an element, the same event is also triggered on all of that element’s ancescors. Event bubbles up from the most nested element (e.g. button) to the root of the DOM (e.g. window); this process is known as event bubbling.

We may define function that handles such event. Originating element (the button) is stored in ‘target’ property of event object. Event object is passed to every function that handles that event and doesn’t change on it’s way to root of the DOM. Using event delegation it is possible to add an event handler to an element, wait for an event bubble up from a child element and easily determine whether it was e.g. clicked.

Often bubbling is unexpected behavior and that’s why JavaScript programmers use event.stopPropagation() – it keeps  event from bubbling any further up into the DOM.

See it live:

Practice

Let’s say we have #gallery containing some images. Our goal is to enlarge image user clicks. Normally we would attach onclick event handler to each <img>:

function clicked(event) {
    new LightBox(event.target.src);
}

Using event delegation we’d arrach similar event handler to #gallery container:

function clicked(event) {
    if(event.target.tagname == 'img') {
        new LightBox(event.target.src);
    }
}

That’s it! We check if the target element is image and create lightbox if so. There’s one little problem. Our lovely Internet Explorer doesn’t pass event object into event handler. Moreover event.target is named event.srcElement. So if we want our code be cross-browser, we are forced to modify it:

function clicked(event) {
    var e = event || window.event;
    var t = e.target || e.srcElement;
    if(t.tagName == 'img') {
        new LightBox(t.src);
    }
}

You may see it in action:

jQuery

has bundled in live function which handles automaticaly event delegating. We use it instead of bind so

$('#gallery img').bind('click', function() {
    new LightBox($(this).attr('src'));
});

becomes

$('#gallery img').live('click', function() {
    new LightBox($(this).attr('src'));
});

Nothing more to do.

MooTools

this framework has also support for event delegation, in ‘more’ package. However usage is little different. We’re adding event to container rather than specific collection of elements. We must additionally use pseudoselector relay:

$("gallery").addEvent("click:relay(img)", function(event, image) {
  // you can reference the element clicked with the second
  // argument passed to your callback
  new LightBox(image.get('src'));
});

Benefits

By delegating events to parent objects you can dramatically increase the efficiency of your pages. Consider the example above. You could attach events to every image in the gallery – which may be hundreds of them. There are less event handlers to setup and reside in memory. This is the big one; better performance and less crashing.

Moreover, we don’t need to re-attach handlers after a DOM update. If your page content is generated dynamically, via Ajax for example, you don’t need to add and remove event handlers as elements are created and destroyed.

We must remember that the blur, focus, load and unload events don’t bubble like other events. We cannot use event delegating along them without some ticks. jQuery developers have solved this issue. Don’t be aware to delegate onBlur and onFocus.

We must be careful in placing delegation function. Attaching it to window element isn’t the best idea. In that case every clicked element would be passed through our event handler.

Useful links

  1. Which element is target of an event?
  2. Event delegation with MooTools
  3. Event delegation with jQuery
  4. Better event delegation for MooTools
  5. Bubbling and Capturing – event order
  6. Event delegation with Prorotype
  7. Event delegation with YUI

Add to Del.cio.us

RSS Feed

Add to Technorati Favorites

Stumble It!


Digg It!

        www.sajithmr.com

  • K. T.
    Author should have mentioned that it is a two stage process - first there's a capture phase and then bubble phase and you may want to listen to both for different reasons. Unfortunately I'm not sure if IE handles it the right way - probably not. Good article otherwise!
blog comments powered by Disqus