Skip to content

Commit a832d0b

Browse files
committed
adding events, using delegate and undelegate
1 parent 6e10415 commit a832d0b

File tree

1 file changed

+162
-0
lines changed

1 file changed

+162
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
---
2+
title: Using Delegate and Undelegate in jQuery
3+
attribution: Jordan Boesch
4+
status: needswork
5+
editrequired: 2
6+
source: http://www.learningjquery.com/2010/03/using-delegate-and-undelegate-in-jquery-1-4-2
7+
---
8+
9+
As some of you have heard, there have been two new methods added in jQuery 1.4.2, [.delegate()](http://api.jquery.com/delegate/) and [.undelegate()](http://api.jquery.com/undelegate/). These methods achieve the same thing as the [.live()](http://api.jquery.com/live/) and [.die()](http://api.jquery.com/die/) methods, they just use a different syntax. For those new to *.live()*, it's a method in jQuery that allows you to attach events to elements that appear in the document as well as elements that will appear in the future. An example would be if you attached a click event via *.live()*:
10+
11+
<div class="example" markdown="1">
12+
$('img.photo').live('click', function(){
13+
lightboxify(this);
14+
});
15+
</div>
16+
17+
Then appended some photos via ajax later on:
18+
19+
<div class="example" markdown="1">
20+
// append an image
21+
$('body').append('<img src="face.jpg" alt="silly face" class="photo"/>');
22+
</div>
23+
24+
The click event would still apply to that new image without having to re-bind the event. Handy, isn't it?
25+
26+
Not too long ago, the *.live()* method was brought up for discussion for a [few](http://forum.jquery.com/topic/jquery-live-jquery-fn-live-discussion) [reasons](http://paulirish.com/2010/on-jquery-live/). One problem discussed is that *.live()* fails when you try to use it alongside traversals like:
27+
28+
<div class="example" markdown="1">
29+
// FAILS
30+
$('ul').find('li').next().live('click', function(){});
31+
// FAILS
32+
$('ul').parent().nextAll().live('click', function(){});
33+
</div>
34+
35+
and also when you pass any native DOM elements like:
36+
37+
<div class="example" markdown="1">
38+
// FAILS
39+
$(document.body).live('click', function(){});
40+
</div>
41+
42+
Unfortunately, when you use *.live()*, it has to be at the top of the chain like so:
43+
44+
<div class="example" markdown="1">
45+
$('ul li').live('click', function(){})
46+
</div>
47+
48+
Because this can be frustrating and confusing for many users who are used to the traversing and chainability that jQuery offers, it sparked a discussion about the syntax for *.live()*. Why does it look like all the other methods, yet does not behave the same? Since changing the syntax would result in a whirlwind of code breakage, the jQuery team decided to introduce *.delegate()* and *.undelegate()* to complement *.live()* and *.die()*. Here's an example of how you would normally use *.live()* and *.die()* and how you can now use *.delegate()* and *.undelegate()*:
49+
50+
Old way
51+
52+
<div class="example" markdown="1">
53+
// Using .live()
54+
$("table").each(function(){
55+
$("td", this).live("hover", function(){
56+
$(this).toggleClass("hover");
57+
});
58+
});
59+
60+
// Using .die()
61+
$("table").each(function(){
62+
$("td", this).die("hover");
63+
});
64+
</div>
65+
66+
New way
67+
68+
<div class="example" markdown="1">
69+
// Using .delegate()
70+
$("table").delegate("td", "hover", function(){
71+
$(this).toggleClass("hover");
72+
});
73+
74+
// Using .undelegate()
75+
$("table").undelegate("td", "hover");
76+
</div>
77+
78+
The benefit of *delegate()* is that it allows you to specify its context. This way, it ensures that we do not bubble all the way up the DOM tree to capture the target of the element. With the .live() method, it bubbles all the way up the DOM each time unless you set context like so: *$('td', $('table')[0]).live('hover', function(){})*. That just looks ugly.
79+
80+
Some often like to think of *delegate()* like a *bind()* call. The syntax is a little different as you can see below.
81+
82+
<div class="example" markdown="1">
83+
// .bind() way
84+
$('ul li').bind('click', function(e){
85+
// Do something with bind
86+
});
87+
88+
// .delegate() way
89+
$('ul').delegate('li', 'click', function(e){
90+
// Do something with delegate
91+
});
92+
</div>
93+
94+
95+
In short, the difference between *.bind()* and *.delegate()* is that *.bind()* will only add events to the elements that are on the page when you call it. .delegate() is listening for new elements and then adding events to them when they appear on the page.
96+
The gotchas of delegate
97+
98+
While it does behave like *.bind()*, it does not allow you to pass an object map of events like *.bind()* does. Take this *.bind()* method for example:
99+
100+
<div class="example" markdown="1">
101+
// This works wonderfully
102+
$('ul li').bind({
103+
click: function(e){
104+
// Something on click
105+
},
106+
mouseover: function(e){
107+
// Something on mouse over
108+
}
109+
});
110+
</div>
111+
112+
An error will be thrown when you try to do:
113+
114+
<div class="example" markdown="1">
115+
// FAILS!
116+
$('ul').delegate('li', {
117+
click: function(e){
118+
// Something on click
119+
},
120+
mouseover: function(e){
121+
// Something on mouse over
122+
}
123+
});
124+
</div>
125+
126+
I'm not sure the reasoning behind not implementing this, but I guess I'm not the only one pondering it.
127+
128+
Granted, *.bind()* didn't have this feature until jQuery 1.4. But if you'd like this same feature in *.live()* and *.delegate()*, Robert Katic wrote a small piece of code that you can include. [Grab the gist here](http://gist.github.com/310747).
129+
130+
I recommend using Robert Katic's patch above, but of course there are other approaches people can take. For example, you can rig up your own custom object map:
131+
132+
<div class="example" markdown="1">
133+
var customObjMap = {
134+
click : function(e){
135+
// Something on click
136+
},
137+
mouseover : function(e){
138+
// Something on mouse over
139+
}
140+
};
141+
142+
$('ol').delegate('li', 'click mouseover', function(e){
143+
if($.isFunction(customObjMap[e.type])){
144+
customObjMap[e.type].call(this, e);
145+
}
146+
});
147+
</div>
148+
149+
Another "gotcha" with both *.delegate()* and *.live()* is that when you add the events *mouseenter* and *mouseleave* to an element, and then check the event type (e.type) in the callback function, it incorrectly displays as *mouseover* and *mouseout*. Using .bind(), on the other hand, it displays as *mouseenter* and *mouseleave* as expected. Here is an example:
150+
151+
<div class="example" markdown="1">
152+
$('ol').delegate('li', 'mouseenter', function(e){
153+
alert(e.type); // outputs mouseover
154+
});
155+
156+
$('ol li').bind('mouseenter', function(e){
157+
alert(e.type); // outputs mouseenter
158+
});
159+
</div>
160+
161+
162+
Overall, the "gothcas" are no match for the benefits that *.delegate()* and *.undelegate()* provide. Truly great additions to the jQuery core.

0 commit comments

Comments
 (0)