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!
You should follow me on Twitter here I tweet about jQuery amongst the usual tweet-splurges!