Just One Of Those Things You Need To Understand About JavaScript

Published by Chris Coyier

Ever since I've published the article Dynamic Page / Replacing Content, I've gotten quite a few emails that come in from people who are trying to use it in conjunction with some other JavaScript stuff and having trouble. Most of the time, it's some kind of lightbox effect. One of their pages has a bunch of thumbnails on it, and when they load that page in, the lightbox effect doesn't work.

The problem is that when the thumbnails are loaded onto the page (via Ajax, i.e. jQuery's .load() function) they do not have any events bound to them.

/* Your lightbox plugin */
$("photos a").ceebox();  

/* Basics of Ajax */
$("nav a").click(function(e) {
    e.preventDefault();
    $("#main-content").load(this.href);  /* Thumbnails loaded from here */
});

The way that the lightbox plugin (probably) works is that it binds click events to the elements you passed in that selector (the thumbnails) when the page loads, and those click events do the lightbox action. Since the newly loaded thumbnails have no click event, the lightbox action does't work.

One way to fix it is to call the lightbox plugin after the content loads, in the callback function of the load function:

$("photos a").ceebox();  

$("nav a").click(function(e) {
    e.preventDefault();
    $("#main-content").load(this.href, function() {

              /* Callback function */
              $("photos a").ceebox();  /* Call this again */

    });
});

A little repetitive, but that'll do the trick.

A Better Way with Delegate

While this is "just how JavaScript works" it's a known pain in the butt. Since jQuery is a library that exists to ease pains like this, of course it has a better way. That way is the .delegate() function, where instead of binding events to the individual elements, you bind an event to an element higher up the DOM tree, which isn't likely to be replaced via Ajax, which watches for those clicks.

This relies on something called event bubbling, which is a neat and important concept in JavaScript (really: the DOM model). If you click on a thumbnail, it will trigger a click event on that element, then a click event on it's parent element, and a click event on it's parent's parent element, all the way up to the root element. Because of this, we can watch for clicks on deeper-down elements from higher-up elements.

Unfortunately with our lightbox example, you would have to alter the plugin itself to get it to use delegate instead of binding directly to the elements. Definitely do-able but trickier, since you probably aren't as intimately familiar with that plugin's code as you are your own.

Listen to Remy Sharp

As this article was drafting, Remy Sharp put out a video screencast about this exact topic. He's way better at explaining it than me, so please go watch that.