Simple use of Event Delegation

Posted on 14th June 2011 — Event delegation may be some techie term that you’d rather shy away from, but if you’ve not already used it, this example will show you a simple but powerful use of event delegation.


Watch Simple Event Delegation (Alternative flash version)

QuickTime version is approximately 22Mb, flash version is streaming.

View the demo used in the screencast

The Problem

We’ve set up our page, we’ve run all our jQuery and we’ve hooked our click handlers. But what happens new new content arrives in the page, say via an Ajax request for instance? Those click handlers don’t work anymore.

We could repeat our code to handle the click each time the Ajax has run, but that feels repetitive doesn’t it? We want our code to by abide by the DRY rule where possible: Don’t Repeat Yourself.

Can’t the container element that holds all the images listen out for clicks instead? Absolutely yes. That’s where event delegation comes in to play.

Our regular code looks something like this:

<!-- all our initial markup, images, etc -->
// when an image in the pictures list is clicked:
$pictures.find('img').click(function () {
  // fade the loading notication in to view
  // then read the source url from the image that
  // was clicked and remove the '_s' from the url
  // which points to the original, larger image.
  var src = this.src.replace(/_s/, '');

  // now create a new image, and set the source
  // and once it's loaded:
  $('<img>').attr('src', src).load(function () {
    // empty the main picture contain and insert
    // *this* image

    // then stop the loading status fade and fade out
    $('#loadingStatus').stop(true, true).fadeOut();

When the Ajax request completes we had to repeat this code to get the images to be clickable – but using the .delegate jQuery function we only have to write this once, and all new images added to the $pictures list will load as we want.

jQuery Delegate

The way jQuery’s delegate method tells a parent element to watch for a particular event, like clicking, and if that event matches a selector you give it.

So instead of doing:

// in the code above this reads as
// $pictures.find('img').click(fn);

We use:

$pictures.delegate('img', 'click', fn);

Telling the $pictures element ($pictures = $('#pictures')) to watch for click events that match the img selector (of course this could be any CSS selector), and if that condition occurs, run the fn function.

Now we can move to the next set of pictures in the example, and clicking the thumbnails still works even though the original images we hooked our click handlers have been since removed.

All very simple!