Search

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

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 -->
<script>
// when an image in the pictures list is clicked:
$pictures.find('img').click(function () {
  // fade the loading notication in to view
  $('#loadingStatus').fadeIn();
  // 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
    $main.empty().append(this);

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

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:

$('img').click(fn); 
// 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!

Related screencasts

Demo

If you find this demo doesn't work as expected, it's possibly due to the demo running from within an iframe. Try running the demo in it's own window.

Source Code

Comments

  1. Aaron H. On 14th June 2011 at 18:06

    Glad to see a new screencast.

    This is really great for instances where fn.live is impractical, but is there a particular reason you wouldn’t use fn.live in this instance?

  2. David Maciejewski On 14th June 2011 at 18:06

    Thanks for sharing this useful piece of code to us!

  3. jody On 14th June 2011 at 20:06

    Would $(’img’).live(’click,’ fn); work in this case too? If I understand .live right (and I might not), seems like it would work as well.

  4. CaptSaltyJack On 14th June 2011 at 21:06

    Or just use $.live() - problem solved :)

  5. DJ On 14th June 2011 at 22:06

    Hooray… you’ve done another tut… we’ve missed you. Actually I’ve never seen this demonstrated so straightforward and succinctly - “please sir, I want some more.”

  6. Remy On 14th June 2011 at 23:06

    Those asking about .live - you’re right, but don’t use .live. It’s best to use .delegate.

    Handy screencast over at net.tutsplus.com explaining why

  7. Matthew Laver On 15th June 2011 at 09:06

    Thanks for the video, really good as usual. I have tended to use .live() in the past. Is this the same? Or rather which situations would you use the two? Thanks.

    Sorry didn’t see the earlier comments…

  8. Anselmo On 15th June 2011 at 15:06

    Hi,

    Other way (little more dry, but without the delegate method):

    $(’#picturescontainer’).click(function(e) { var tgt = $(e.target); #get the closest img var _img = tgt.closest(’img’); # possible filter here if (img.hasClass(’somefilteredclassifwanted’)) { # call the load content here… } });

    I’m keep using this approach for dynamic content, however i really don´t know what is the performance price.

    Cheers

  9. RedOnion On 16th June 2011 at 12:06

    Great tutorial, didn’t know about that. My solution had been to define a function which did all of the attaching of listeners and then call that every time the content was reloaded.

    Never liked it…

    This is great though, thanks!

  10. Bastian On 16th June 2011 at 17:06

    Ah, thanks for this! I just ran into the same problem some days ago and yes… i solved it with copy and paste. U-uh… now I’m reformed. ;-)

  11. jody On 17th June 2011 at 17:06

    Thanks for linking to the screencast–that cleared the mud for me and made your tutorial all the more useful. Since watching that and your tutorial I’ve been doing some serious code cleaning.

  12. Yosy On 23rd June 2011 at 01:06

    Hi Remy, you mentioned that event delegation can helps when the DOM is changing, I agree but in addition event delegation for example can help when you have a big table with a lot of rows and you want to give the user option to change the content in the cell. For this example,event delegation would be great instead of RxC(rows multiplied by columns) events (click event for each cell).

    A little tip for the next time - first show how it works,If you know how something works behind the scenes you can use it`s full advantage.

    Thanks a lot for the screencasts, Yosy

  13. Matt On 1st July 2011 at 17:07

    Thanks so much for these great screencasts! Do you know if this will show up in the iTunes feed in the future? The latest one there is the previous screencast (Populate Select Boxes).

  14. Russell On 25th August 2011 at 12:08

    Thanks for this video, I had previously been using .live but will switch to .delegate having seen this. Reading the other comments it looks as if I was not alone in using .live. I think this is probably because .live was introduced in 1.3 and .delegate was introduced in 1.4.

  15. Russell On 25th August 2011 at 12:08

    On a separate note…. it would be nice to know which tags are available to use here in the comments. Thanks again for the vid.

  16. MathieuL On 22nd September 2011 at 13:09

    What’s the difference between .delegate() and .live()?

Comments are now closed.