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.
First, it helps to visualize the DOM tree of an HTML document. A simple HTML page would look like this:
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.
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.
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()
.
$('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.
$('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(...);
$('#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.
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() });
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.
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',...)
.
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.
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
:
bind
directly binds handlers to the individual elements, it cannot bind them to elements that aren't on the page yet. If you were to run $('a').bind(...)
, and then new links were added to the page via AJAX, your bind handler would not work for these. live
and delegate
on the other hand are bound to another ancestor node, so it will work for any element exists now or in the future within that ancestor element.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.
Comments are loading...