The Difference Between jQuery's .bind(), .live(), and .delegate()

01 February 2011

The difference between .bind(), .live(), and .delegate() is not always apparent. Having a clear understanding of all the differences, though, will help us write more concise code and prevent bugs from popping up in our interactive applications.

The jQuery team have announced in v1.7 a new method for binding events called on. This method combines the functionality of live, bind, and delegate described below, allowing you to specify the binding method based the arguments passed rather than by using different function names.

The basics

The DOM tree

First, it helps to visualize the DOM tree of an HTML document. A simple HTML page would look like this:

HTML DOM Structure

Event bubbling (aka event propagation)

When we click a link, it fires the click event on the link element, which triggers any functions we bound to that element's click event.

$('a').bind('click', function() { alert("That tickles!") });

So a click will trigger the alert.

HTML DOM Structure

That click event then propagates up the tree, broadcasting to the parent element and then to each ancestor element that the click event was triggered on one of the descendent elements.

HTML DOM Structure

In the context of manipulating the DOM, document is the root node.

Now we can more easily illustrate the difference between .bind(), .live(), and .delegate().

.bind()

$('a').bind('click', function() { alert("That tickles!") });

This is the most straight forward binding method. jQuery scans the document for all $('a') elements and binds the alert function to each of their click events.

.live()

$('a').live('click', function() { alert("That tickles!") });

jQuery binds the alert function to the $(document) element, along with 'click' and 'a' as parameters. Any time an event bubbles up to the document node, it checks to see if the event was a click and if the target element of that event matches the 'a' CSS selector. If both are true, the function executes.

The live method can also be bound to a specific element (or "context") other than document, like this:

$('a', $('#container')[0]).live(...);

.delegate()

$('#container').delegate('a', 'click', function() { alert("That tickles!") });

jQuery scans the document for $('#container'), and binds the alert function along with the click event and 'a' CSS selector as parameters. Any time an event bubbles up to $('#container'), it checks to see if the event was a click and if the target element of that event matches the CSS selector. If both checks are true, it executes the function.

Notice this is similar to .live(), except that it binds the handler to the specified element instead of the document root. The astute JS'er might conclude that $('a').live() == $(document).delegate('a'), right? Well, no, not exactly.

Why .delegate() is better than .live()

jQuery's delegate method is generally preferred to the live method for a few reasons. Consider the following examples:

$('a').live('click', function() { blah() });
// or
$(document).delegate('a', 'click', function() { blah() });

Speed

The latter is actually faster than the former, because the former first scans the entire document for all $('a') elements, storing them as jQuery objects. Even though the live function only needs to pass 'a' through as string argument to be evaluated later, the $() function doesn't "know" that the chained method is going to be .live().

The delegate method on the other hand, only needs to find and store the $(document) element.

One hack to get around this is to call the live binding outside of the $(document).ready() state, so that it runs immediately. That way it will run before the DOM gets populated, and thus won't find the elements or create the jQuery objects.

Flexibility and chain-ability

The live function is also convoluted. Think about it; it's chained to the $('a') object set, but it's actually acting on the $(document) object. For this reason, it can get hairy trying to chain methods to it. In fact, I'd argue the live method would make more sense as a global jQuery method in the form of $.live('a',...).

CSS selector only

And finally, the live method has a very large shortcoming, and that is that it can only operate on a direct CSS selector string. This makes it very inflexible.

For more on the CSS selector shortcoming, see Exploring jQuery .live() and .die().

Update: Thanks to pedalpete on Hacker News and Ellsass below in the comments for reminding me to add this next section.

Why .live() or .delegate() instead of .bind()

After all, bind seems so much clearer and more direct, doesn't it? Well, there are 2 reasons we prefer delegate or live to bind:

Stopping propagation

I'd like to mention one last note concerning event propagation. Typically, we can stop other handler functions from running by using event methods like:

$('a').bind('click', function(e) {
  e.preventDefault();
  // or
  e.stopPropagation();
});

However, when we use the live or delegate methods, the handler function won't actually run until the event bubbles to the element to which the handler is actually bound. By this time, our other handler functions from .bind() have already run.

About the author:

Steve Schwartz // Owner of Alfa Jango Web-based Software, creator of RateMyStudentRental & LeadNuke, engineer, hacker, rubyist, guitarist, aspiring racecar driverist.



Comments are loading...