jQuery Event Delegation

A normal event handler works only for the elements which exist when you attach it. If you add new elements later (with append, or from Ajax), they do not get the handler. The solution is event delegation.

The problem

<ul id="todo">
  <li>Buy milk</li>
</ul>
var clicks = 0;
$('#todo li').on('click', function () { clicks++; });   // direct handler

$('#todo').append('<li>Pay bill</li>');                  // new element
$('#todo li').eq(1).trigger('click');                    // click on the new item
console.log('Clicks counted: ' + clicks);
Console output

Clicks counted: 0

The new item was not counted. It did not exist when we attached the handler.

The solution: delegated handler

Attach the handler to a parent which always exists, and give a selector as the second argument. jQuery checks if the click came from a matching child.

<ul id="todo">
  <li>Buy milk</li>
</ul>
var clicks = 0;
$('#todo').on('click', 'li', function () {
  clicks++;
  console.log('Clicked: ' + $(this).text());
});

$('#todo').append('<li>Pay bill</li>');
$('#todo li').eq(1).trigger('click');
$('#todo li').eq(0).trigger('click');
console.log('Clicks counted: ' + clicks);
Console output

Clicked: Pay bill
Clicked: Buy milk
Clicks counted: 2

Now both the old and the new items work.

How it works

Events “bubble up”: a click on the li goes also to the ul and then to its parents. The parent handler receives the event, checks if the real target matches the selector li, and then runs your function with this as that li.

Benefits

  • Works for elements which are added later.
  • Uses only one handler for many elements, so it saves memory on big lists and tables.
  • Good for lists, tables and menus built by Ajax.

Which parent should I use?

Use the closest parent which is always on the page, like the list or the table. Using document works too, but it is slower for a big page, because every event must be checked.

Remove a delegated handler

$('#todo').off('click', 'li');

The old methods

The old methods .live() (removed long ago), .delegate() and .bind() (still present but deprecated) are replaced by .on(). Use .on() for all of them. See jQuery 4 and Upgrading.

Note: A tip: if a button added by Ajax does nothing when clicked, you probably need event delegation. Next: jQuery Effects.

Congratulations! Chapter Finished. Learn more about the similar topics:
Exercises & Assignments
No Content Found.
Interview Questions & Answers
No Content Found.