Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 90 additions & 49 deletions page/events/event-delegation.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,93 @@
title : Increasing Performance with Event Delegation
attribution: jQuery Fundamentals
---
You'll frequently use jQuery to add new elements to the page, and when you do,
you may need to bind events to those new elements — events you already bound to
similar elements that were on the page originally. Instead of repeating your
event binding every time you add elements to the page, you can use event
delegation. With event delegation, you bind your event to a container element,
and then when the event occurs, you look to see which contained element it
occurred on. If this sounds complicated, luckily jQuery makes it easy with its
`$.fn.live` and `$.fn.delegate` methods.

While most people discover event delegation while dealing with elements added
to the page later, it has some performance benefits even if you never add more
elements to the page. The time required to bind event handlers to hundreds of
individual elements is non-trivial; if you have a large set of elements, you
should consider delegating related events to a container element.

<div class="note" markdown="1">
### Note

The `$.fn.live` method was introduced in jQuery 1.3, and at that time only
certain event types were supported. As of jQuery 1.4.2, the `$.fn.delegate`
method is available, and is the preferred method.
</div>

<div class="example" markdown="1">
Event delegation using `$.fn.delegate`

$('#myUnorderedList').delegate('li', 'click', function(e) {
var $myListItem = $(this);
// ...
});
</div>

<javascript caption="Event delegation using `$.fn.live`">
$('#myUnorderedList li').live('click', function(e) {
var $myListItem = $(this);
// ...
});
</javascript>

### Unbinding Delegated Events

If you need to remove delegated events, you can't simply unbind them. Instead,
use `$.fn.undelegate` for events connected with `$.fn.delegate`, and `$.fn.die`
for events connected with `$.fn.live`. As with bind, you can optionally pass
in the name of the bound function.<javascript caption="Unbinding delegated events">
$('#myUnorderedList').undelegate('li', 'click');
$('#myUnorderedList li').die('click');</javascript>
<div class="example" markdown="1">
</div>

Say you have to add new line items to your page, given the following html:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"list items" or " <li>" please.
Capitalize HTML

```
<html>
<body>
<div id="container">
<ul id="list">
<li>
<a href="#">Item #1</a>
</li>
<li>
<a href="http://somedomain.com">Item #2</a>
</li>
<li>
<a href="#">Item #3</a>
</li>
<li>...</li>
<li>
<a href="http://someotherdomain.com">Item #100</a>
</li>
</ul>
</div>
</body>
</html>
```

We need to attach the same Event Listener 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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change "Event Listener" to "event handler", in lowercase


We can attach a direct bind click event to each `li` that will alert the text inside of it by doing the following:
```
// attach a directly bound event
$('#list a').on('click', function(event) {
event.preventDefault();
console.log( $(this).text() );
});
```

While this works perfectly fine, there are drawbacks. Consider this:
```
// add a new element on to our existing list
$('#list').append('<li><a href="http://newsite.com">Item #101</a></li>');
```
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')`

## Event Propagation
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:

* `a` tag
* `li` tag
* `ul` tag
* `div` tag
* `body` tag
* `html` tag
* document root

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_.

Since we know how events bubble we can created a delegated event that listens for a specific event to happen on our element
```
// attach a delegated event
$('#list').on('click', 'a', function(event){
event.preventDefault();
console.log( $(this).text() );
});
```
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 on our `ul` tag instead of an unknown number of direct events on our `a` tags.

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`.
```
// attach a delegated event
$('#list').on('click', 'a', function(event){
var $elem = $(this);
if( $elem.is('[href^=http]') ){
$elem.attr('target', '_blank');
}
});
```
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 followin the `href`)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"following," not "followin" :)


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.
```
// attach a delegated event with a more refined selector
$('#list').on('click', 'a[href^=http]', function(event){
$(this).attr('target', '_blank');
});
```

##Summary
Event Delegation is the processing of listening for Bubbling Events. It allows us to attach a single Event Listener for elements that exist now or in the future.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace first sentence with "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."
Also, don't capitalise Event Listener


Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove blank line