Why You Should Never Use jQuery Live

Event delegation is a powerful technique that is often used in JavaScript applications. jQuery has two similar API methods that provide similar event delegation functionality - live and delegate.

posted in jquery, Development on April 06, 2011 by Justin Meyer

Event delegation is a powerful technique that is often used in JavaScript applications. jQuery has two similar API methods that provide similar event delegation functionality: live and delegate.

On the surface live and delegate can seem interchangeable. However, they are not. Live has several serious disadvantages and should never be used, and this article will explain why.

Event Delegation 101

First, a quick review. Event delegation works by binding to an element in the page, waiting for a DOM event to bubble to this element, and in the event handler, checking if a parent of the target element matches a selector you are looking for. If a match is found, your handler is called.

For example, if you want to ‘manually’ delegate on clicks for “tr” elements inside a table with the ID attribute “mytable”, you might do something like:

$("#mytable").bind('click', function(ev){
  var current = ev.target
  while( !/tr/i.test(current.nodeName) && 
         current !== this ){
    current = current.parentNode
  }
  if( current !== this ){
    // do stuff !!
  }
})

How Live and Delegate Work

Here’s similar code but done with jQuery’s delegate and live:

$('#mytable').delegate('tr', 'click', function(event) {…});
$('#mytable tr').live('click', function(event) {…});

The critical difference is .live binds to the document element while delegate binds to whatever element its called on, in this case the #mytable element.

In the delegate example above, when a user clicks inside a tr element, this event bubbles up to the table, which triggers the delegate click handler. There it checks if the any of the event’s target’s parents (or the target itself) matches the selector, “tr”. If it does, it runs the delegate event handler.

In the live example, jQuery binds a click handler to the top-most element in the DOM, the document element. Any click in the page will bubble up the DOM to this element and trigger this click handler. It will check if the elements above the thing we clicked, or the event target itself, match “#mytable tr”. Assuming the user clicked a tr or something inside a tr within #mytable, its parent chain will contain a match, so the live callback will run.

Now that its clear how they work, we can discuss how live could cause problems in your application.

1. You can’t use live for reusable widgets.

Let’s say we are creating a tab widget. We want to delegate on all div.tab clicks inside our widget. Since live binds to the document element, if we put 2 tab widgets in the page, both of their click handlers will ALWAYS be invoked. This is not what we want! With delegate, we can listen ONLY on the tab widget’s parent element, so clicking the first tab widget will not invoke the click handler of the second widget.

<html>
  <div class=”tab1 tabwidget”>
    <div class=”tab”>…</tab>
    <div class=”tab>…</tab>
  </div>
<div class=”tab2 tabwidget”>
    <div class=”tab”>…</tab>
    <div class=”tab>…</tab>
  </div>
</html>

Live binds to the HTML element, so in a sense all live handlers are “global”. Delegate only listens to .tab1 or .tab2, so it is localized to only the widget we’re working on.

2. stopPropagate() doesn’t work in live

As illustrated above, live actually binds an event handler to the top element in the page, so calling stopPropagate won’t do anything. The event has already traveled as far as it can propagate.

By contrast, calling stopPropagate in a delegate handler will prevent the event from bubbling above the tab’s parent element.

3. Live is slower

Returning to the code sample above, the live example will do a query for all “#mytable tr a” elements in the page, then ignore that result and bind to the document element. This first query is completely useless and wasteful.

Also, live traverses all DOM nodes between the event target and the document element to check for a match with the given selector. Delegate only traverses DOM nodes between the event target and the given parent element to check for a match. Traversing parent elements in the DOM is the slowest part of event delegation, so live handlers will be slower to respond to events.

4. Live isn’t chainable

Everyone is used to chaining jQuery methods together and not thinking twice about it. Live breaks chaining functionality, which might introduce tricky bugs. Since that first query is used as the selector for the live handler, the context gets changed, so chaining a method after a .live() call won’t do what you expect.

Rolling your own

You might be thinking, who needs delegate when I can do this myself? You can certainly write your own event delegation, like this:

$(“#mytable”).bind(“click”, function(ev){
  var $a = $(event.target).closest(“tr a”);
  if($a.length) // we have a match, run the click code
});

The disadvantage to this becomes apparent when you delegate for multiple selectors on the same parent element. For example, say you want to bind to all “tr a .edit” selectors in your table also. If you’re using delegate, it will batch the .closest call (which is the slowest part of event delegation). If you roll your own handlers, you’ll end up with multiple calls to .closest, which means walking up the parent tree more times than is needed, so your event delegation performance will suffer.

Conclusion

As a general best practice, never use .live in your applications. After live was introduced in jQuery, Justin argued the need for better a event delegation API, and delegate was created. The main reason jQuery still supports live is for legacy code.

comments powered by Disqus
Contact Us
(312) 620-0386 | contact@bitovi.com
 or cancel