Disclaimer: I will assume that readers know some basic JavaScript http://www.w3schools.com/js/default.asp) and a bit of jQuery knowledge as well (Getting Started with jQuery – can be found at http://docs.jquery.com/Tutorials)
What is event delegation? to understand this, one needs to know a JavaScript feature called event bubbling in DOM. Quick explanation, when user trigger an event on an element in a page, a click for example. The action will trigger the same type of event (click event) for that element’s ancestor nodes.
A brief example. If we have a chunk of HTML code as shown below.
<table>
<tbody>
<tr>
<td>
<input type="button"/>
</td>
</tr>
</tbody>
</table>
When user clicks on <input type=”button”/>, browser would run event handler for event type click which is bound to <input type=”button”/>. Then it will run event handler for the same event type which is bound to its ancestors in this order: <td> – <tr> – <tbody> – <table> – etc. To know more of event bubbling, quirk’s blog has a comprehensive explanation on the topic. http://www.quirksmode.org/js/events_order.html
Because of this feature, it’s possible for us to bind an event handler to a parent node of a target element instead of bind directly to that target element. This is what we call event delegation.
Why would we want to do event delegation? Consider this scenario where we need to add new elements dynamically, and each of these elements need to behave in a same fashion.
Though it seems natural, one might be tempted to use jQuery selector to encapsule all the dynamically-added elements and then bind it to a function. The bad news is: all elements added after executing the bind will not have the function event handler to be bound to them. One can simply solve the problem simply by binding function whenever a new element is added. Note that in this solution, event binding is executed for every element.
Another possible solution is (as you might guess) to use event delegation. Since an event will bubble up to its ancestors, we can bind an event handler function to the nearest common ancestor of these dynamically-added elements. What function needs to do now is only to recognize what is the event’s target element and then execute an appropriate handler. Note that in this solution, event binding is done only once (to the common ancestor).
Example: When ‘add’ button is clicked, a new row is added. Clicking on a ‘remove’ text in a row will remove that particular row.
<input id="btn"type="button" value="add"/>
<table id="test">
<tbody>
</tbody>
</table>
First solution (without event delegation) :
$("#btn").click(function(){
var newRow = $(
"<tr><td><span class='removeRow'>remove</span></td></tr>");
//create new element
//for further explanation see jQuery(html, [owner document])
//documentation at http://api.jquery.com/jQuery/
$("#test > tbody").append(newRow);
newRow.find(".removeRow").click(function() {
//using .closest(selector) would be more efficient if a long
//ancestor traversal is needed.
$(this).parent().parent().remove();
});
});
Second solution (with event delegation):
$("#btn").click(function(){
$("#test > tbody").append(
"<tr><td><span class='removeRow'>remove</span></td></tr>");
});
$("#test").click(function(event) {
var elem = $(event.target).closest(".removeRow");
//.closest() is used because user might click on a descendant
//element.
elem.parent().parent().remove();
});
Since jQuery 1.3, event delegation can be easily done with .live() function. Hence we can omit the $(event.target).closest(…) part.
$("#btn").click(function(){
$("#test > tbody").append(
"<tr><td><span class='removeRow'>remove</span></td></tr>");
});
$(".removeRow").live("click", function() {
$(this).parent().parent().remove();
});
As of jQuery 1.4.2, another useful method called .delegate() is added to jQuery library. It is more efficient than .live() because it allows user to select which DOM element should the event handler be bound to, as opposed to .live() which binds strictly to root DOM element.
$("#btn").click(function(){
$("#test > tbody").append(
"<tr><td><span class='removeRow'>remove</span></td></tr>");
});
$("#test").delegate(".removeRow", "click", function() {
$(this).parent().parent().remove();
});
For further information on .live() and .delegate(), please read their respective documentations from jQuery’s official page (http://docs.jquery.com/Main_Page)
Warning
As mentioned before, event delegation relies on event bubbling in order to work. It doesn’t work for events that don’t bubble like focus, or blur. You may refer to http://en.wikipedia.org/wiki/DOM_events to see the whole list of events and their related information.
Notes: If you’re too lazy to setup your own HTML file + importing jQuery library, you may use online JavaScript debuggers e.g. http://jsfiddle.net/ or http://jsbin.com/