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.
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.
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.
It’s the age old (well, in webby terms) issue of how to populate one select box based on another’s selection. It’s actually quite easy compared with the bad old days, and incredibly easy with jQuery and a dash of Ajax.
There’s a fairly common case to have one select box driving the content of another. Or in fact, something driving the contents of a select box. Perhaps you’ve got categories like “easy”, “medium” and “hard”, like the categories used on this site. When someone selects “easy”, a select box populates with all the jQuery for Designers articles that are marked as easy.
Sometimes that second select box has it’s contents hidden in the page already, and sometimes you’ll want it to be called dynamically.
Think of it like this: if JavaScript is disabled, how do you want the visitor to use your page?
Let’s say for arguments sake, if JavaScript is disabled, the user sees a select box with the categories with a next button:
When the visitor hits next, it reloads to show them the article list to read:
Remember this is a contrived example for this tutorial. In practise, for SEO, I wouldn’t use a form to expose a list of my articles, equally there’s no way of going back to the state with the “next” button, etc. So please, if you’re starting out, don’t use this as a way to native your site.
What I really want to show you is how to progressively enhance this page using jQuery to dynamically populate these lists. However, what the screencast will also show you is how easy it is to include this kind of functionality for a prototype demo.
Tasks
Since we’re progressively enhancing the page, I want to remove the form’s default functionality, and replace it with my own. So the tasks are:
When the category is changed make an Ajax request
Take that Ajax response and insert it in to the articles select box
If the articles select box doesn’t exist, we need to create it for the first time
Update the form buttons, so that “next” doesn’t submit, and a “read” button appears when the article select is populated
Ajax Responders
Keeping it simple (and very much contrived), I’ve created three files that contain the articles that we want to display in the select box. Each called “select-boxes-easy.html“, “select-boxes-medium.html” and “select-boxes-hard.html” – as you can see the category name is in the filename. Here’s what easy looks like:
Note that the screencast doesn’t run in the same order. In fact, it will show you how to populate quickly first. For the written tutorial, I want to take you through each step to getting this effect working.
In this example, I put jQuery right before the </body> tag and directly below jQuery, I start my new <script> tag where our code will sit:
Inside of the $(document).ready we want to say: “when the select box changes, make an Ajax request to load the article select box”:
$('#category').change(function () {
var categoryName = $('#category').val();
// for now, let's assume that <select id="articles"> exists
// so our Ajax url could look like: select-boxes-medium.html
$('#articles').load('select-boxes-' + categoryName + '.html');
});
Here I’m using the load method to take the contents of the file I’m requesting, and squirting it straight in to the $('#article') element – which, right now, doesn’t exist. So let’s create that now.
3. Create the article select box
We’ll create an empty variable: $article, and when the category is changed for the first time, we check to see if $article is null, and if it is, we create the article select box and assign it to $article (therefore preventing it from being created again):
var $article = null;
$('#category').change(function () {
var categoryName = $('#category').val();
if ($article == null) {
$article = $('<select id="article" name="article"></select>').appendTo('form');
}
// note that now we're point to the $article variable
$article.load('select-boxes-' + categoryName + '.html');
});
Now the form is working and creating the second select box properly, all we have to do is tidy up some of the buttons, since currently the “next” button submits the form.
4. Buttons
There’s three things we need to do:
Change the “next” submit button to a “button” button
If “next” is clicked, pretend like the category was changed (note: this part was accidentally omitted from the screencast)
Add a “read” button (which if we were progressively enhancing a real page, this would appear when the category was submitted the first time)
The code needs the following added to the end:
var $next = $('#next');
$next[0].setAttribute('type', 'submit'); // note: this is required due to a bug in jQuery
// note that this part is not in the screencast
$next.click(function () {
$('#category').change();
});
Now inside of the Ajax request, we change the part that creates the article select for the first time and add:
You can check out the final product and the final working version – but please, please remember this is a contrived example, only designed to show you how easy it is to populate on select box with another.
You should follow me on Twitter hereI tweet about jQuery amongst the usual tweet-splurges!
There are a few websites I’ve seen lately that have a left hand navigation automatically updates it’s selection based on where you’ve scrolled to on the page. This tutorial will show you exactly how to achieve just that.
Most of us have to make our web pages work in The Big Five browsers, so I thought it was about time I introduce you to the debugging tools for each of those browsers with a couple of tips thrown in to the mix.
As we build more and more Ajaxy applications, and our apps reside on a single page, the browser’s native back button can get more and more broken. This episode will show you how to re-enable the back button on your apps.
Watch
Watch Enabling the Back Button screencast (Alternative flash version)
QuickTime version is approximately 50Mb, flash version [...]