|
1 | 1 | ---
|
2 |
| -title : Increasing Performance with Event Delegation |
3 |
| -level: beginner |
| 2 | +title : Understanding Event Delegation |
| 3 | +attribution: jQuery Fundamentals |
4 | 4 | ---
|
5 |
| -You'll frequently use jQuery to add new elements to the page, and when you do, |
6 |
| -you may need to bind events to those new elements — events you already bound to |
7 |
| -similar elements that were on the page originally. Instead of repeating your |
8 |
| -event binding every time you add elements to the page, you can use event |
9 |
| -delegation. With event delegation, you bind your event to a container element, |
10 |
| -and then when the event occurs, you look to see which contained element it |
11 |
| -occurred on. If this sounds complicated, luckily jQuery makes it easy with its |
12 |
| -`$.fn.live` and `$.fn.delegate` methods. |
13 |
| - |
14 |
| -While most people discover event delegation while dealing with elements added |
15 |
| -to the page later, it has some performance benefits even if you never add more |
16 |
| -elements to the page. The time required to bind event handlers to hundreds of |
17 |
| -individual elements is non-trivial; if you have a large set of elements, you |
18 |
| -should consider delegating related events to a container element. |
19 |
| - |
20 |
| -<div class="note" markdown="1"> |
21 |
| -### Note |
22 |
| - |
23 |
| -The `$.fn.live` method was introduced in jQuery 1.3, and at that time only |
24 |
| -certain event types were supported. As of jQuery 1.4.2, the `$.fn.delegate` |
25 |
| -method is available, and is the preferred method. |
26 |
| -</div> |
27 |
| - |
28 |
| -``` |
29 |
| -// Event delegation using `$.fn.delegate` |
30 |
| -$('#myUnorderedList').delegate('li', 'click', function(e) { |
31 |
| - var $myListItem = $(this); |
32 |
| - // ... |
| 5 | + |
| 6 | +Say you have to add new line items to your page, given the following HTML: |
| 7 | +``` |
| 8 | +<html> |
| 9 | + <body> |
| 10 | + <div id="container"> |
| 11 | + <ul id="list"> |
| 12 | + <li> |
| 13 | + <a href="#">Item #1</a> |
| 14 | + </li> |
| 15 | + <li> |
| 16 | + <a href="http://somedomain.com">Item #2</a> |
| 17 | + </li> |
| 18 | + <li> |
| 19 | + <a href="#">Item #3</a> |
| 20 | + </li> |
| 21 | + <li>...</li> |
| 22 | + <li> |
| 23 | + <a href="http://someotherdomain.com">Item #100</a> |
| 24 | + </li> |
| 25 | + </ul> |
| 26 | + </div> |
| 27 | + </body> |
| 28 | +</html> |
| 29 | +``` |
| 30 | + |
| 31 | +We need to attach the same event handler to multiple elements. In this example we want to attach an event that will the log the text of the anchor tag to the console whenever it is clicked. |
| 32 | + |
| 33 | +We can attach a direct bind click event to each `<li>` using the `.on()` method, that will alert the text inside of it by doing the following: |
| 34 | +``` |
| 35 | +// attach a directly bound event |
| 36 | +$('#list a').on('click', function(event) { |
| 37 | + event.preventDefault(); |
| 38 | + console.log( $(this).text() ); |
33 | 39 | });
|
34 | 40 | ```
|
35 | 41 |
|
| 42 | +While this works perfectly fine, there are drawbacks. Consider this: |
| 43 | +``` |
| 44 | +// add a new element on to our existing list |
| 45 | +$('#list').append('<li><a href="http://newsite.com">Item #101</a></li>'); |
36 | 46 | ```
|
37 |
| -// Event delegation using `$.fn.live` |
38 |
| -$('#myUnorderedList li').live('click', function(e) { |
39 |
| - var $myListItem = $(this); |
40 |
| - // ... |
| 47 | +If we were to click our newly added item, nothing would happen. This is because of the directly bound event that we attached previously. Direct events are only attached to elements at the time we called the `.on()` method for our existing collection of `<a>`'s, that is only the `<a>`'s that were found when we call `$('#list a')` |
| 48 | + |
| 49 | +## Event Propagation |
| 50 | +Understanding how events propagate is an important factor in being able to leverage Event Delegation. Any time an anchor tags is clicked, a *click* event is fired for the: |
| 51 | + |
| 52 | +* `<a>` |
| 53 | +* `<li>` |
| 54 | +* `<ul>` |
| 55 | +* `<div>` |
| 56 | +* `<body>` |
| 57 | +* `<html>` |
| 58 | +* *document* root |
| 59 | + |
| 60 | +Anytime one of these links is clicked you can think of it as if you were clicking the entire document body. This is called *event bubbling* or *event propagation*. |
| 61 | + |
| 62 | +Since we know how events bubble we can created a delegated event that listens for a specific event to happen on our element |
| 63 | +``` |
| 64 | +// attach a delegated event |
| 65 | +$('#list').on('click', 'a', function(event){ |
| 66 | + event.preventDefault(); |
| 67 | + console.log( $(this).text() ); |
41 | 68 | });
|
42 | 69 | ```
|
| 70 | +Notice for the second parameter to the `.on()` method we are telling it which selector to listen for. Now when a *click* event is triggered on our `<ul>`, our delegated event will check to see if the triggering element matches our selector (`'a'`). If it does, our anonymous function will execute. We have now attached a single *click* event listener to our `<ul>` instead of an unknown number of directly bound events on our `<a>`'s. |
43 | 71 |
|
44 |
| -### Unbinding Delegated Events |
| 72 | +Now lets say that whenever a link is clicked we want to check and see if the `href` attribute starts with "http" and if it does we want to set the `target` attribute to `_blank`. |
| 73 | +``` |
| 74 | +// attach a delegated event |
| 75 | +$('#list').on('click', 'a', function(event){ |
| 76 | + var $elem = $(this); |
| 77 | + if( $elem.is('[href^=http]') ){ |
| 78 | + $elem.attr('target', '_blank'); |
| 79 | + } |
| 80 | +}); |
| 81 | +``` |
| 82 | +This simply passes the `.is()` method a selector to see if the element's `href` attributes starts with "http". Also we have removed the `event.preventDefault();` statement, this is because we want the default action to happen (which is to following the `href`) |
45 | 83 |
|
46 |
| -If you need to remove delegated events, you can't simply unbind them. Instead, |
47 |
| -use `$.fn.undelegate` for events connected with `$.fn.delegate`, and `$.fn.die` |
48 |
| -for events connected with `$.fn.live`. As with bind, you can optionally pass |
49 |
| -in the name of the bound function. |
| 84 | +We can actually take this a step further and make our code simpiler and more concise by allowing the selector argument to `.on()` do our logic for us. |
50 | 85 | ```
|
51 |
| -// Unbinding delegated events |
52 |
| -$('#myUnorderedList').undelegate('li', 'click'); |
53 |
| -$('#myUnorderedList li').die('click'); |
| 86 | +// attach a delegated event with a more refined selector |
| 87 | +$('#list').on('click', 'a[href^=http]', function(event){ |
| 88 | + $(this).attr('target', '_blank'); |
| 89 | +}); |
54 | 90 | ```
|
| 91 | + |
| 92 | +##Summary |
| 93 | +Event delegation refers to the process of using event bubbling to handle events at a higher level in the DOM than the element on which the event originated. It allows us to attach a single event listener for elements that exist now or in the future. |
0 commit comments