YUI Library Home

Site Search (YDN & YUIBlog):

# YUI Library Examples: Event Utility: Using Event Utility and Event Delegation to Improve Performance

# Event Utility: Using Event Utility and Event Delegation to Improve Performance

Event delegation is a technique whereby you use a single event handler on a parent element to listen for interactions that affect the parent's descendant elements; because events on the descendant elements will bubble up to the parent, this can be a reliable and extremely efficient mitigation strategy for reducing the number of resource-consuming event handlers you have on any given page. (You can read more about Event Delegation in this YUIBlog article.)

In the example below, mousing over an item in the list will change its background color to yellow. Clicking an item will change its background color to red. Because we're using event delegation, only one event listener is needed for each type of event (`click`, `mouseover`, and `mouseout`), regardless of the size of the list. To illustrate this point, click the "Add Item" button to append more items to list. An infinite number of items can be added to the list, and still just one `click`, `mouseover`, and `mouseout` event handler is required to highlight the items.

View example in new window.

- List Item 1
- List Item 2
- List Item 3
- List Item 4
- List Item 5

## Understanding Event Delegation

Event delegation refers to the use of a single event listener on a parent object to listen for events happening on its children (or deeper descendants). Event delegation allows developers to be sparse in their application of event listeners while still reacting to events as they happen on highly specific targets. This proves to be a key strategy for maintaining high performance in event-rich web projects, where the creation of hundreds of event listeners can quickly degrade performance.

This example illustrates the use of event delegation (via the Event Utility) on `click`, `mouseover`, and `mouseout` events. The problem we will solve here involves reacting to `click`, `mouseover`, and `mouseout` events on list items. As there can be many list items, we want to be frugal in applying event listeners. At the same time, we want to know exactly which `<li>` was involved in a `click`, `mouseover`, and `mouseout` event.

To do this, we'll rely on DOM event bubbling — the process by which an event progresses from its direct target up through the target's node ancestry until it reaches the `window` object. The graphic below may help to illustrate the flow: In this case, we'll count on the fact that a click or a mouseover on (A) the text node within an `<li>` progresses to the `<li>` element itself (B), then to the `<ul>` element (C), and then to the list's parent `<div>` (D) and so on up the document:

## Getting Started

Because events flow this way, we can count on events happening to our `<li>s` bubbling up to our <div> whose ID attribute is "container."

We'll start with some structural markup — a `<div>` containing a `<ul>` with 5 `<li>` children.

<div id="container"> <ul id="list"> <li id="li-1">List Item 1</li> <li id="li-2">List Item 2</li> <li id="li-3">List Item 3</li> <li id="li-4">List Item 4</li> <li id="li-5">List Item 5</li> </ul> </div>

## Event Delegation Made Easy

The Event Utility makes using event delegation easy by providing a `delegate` method that enables the use of CSS selector syntax to define the descendants of the delegation container for which the event listener should be called. Note: Event's delegation functionality is packaged separately in an event-delegate module, which itself requires the Selector Utility.

To use the `delegate` method, pass the id of the element that is the delegation container as the first argument (in this case `<div id="container">`). The second argument is the type of event you want to delegate, and the third is the event listener. The forth argument is a CSS selector that defines the descendant elements that must match the target of the event in order for the listener to be called.

First we'll add the event listener used to highlight each item when it is clicked. As we're only really interested in clicks on `<li>`s, we'll specify a CSS selector of "li" as the fourth argument to the `delegate` method. The element that matched the CSS selector will be passed as the second argument to the event listener. The element that is the delegation container for the listener is passed as the third argument:

(function() { var Dom = YAHOO.util.Dom, Event = YAHOO.util.Event; var onLIClick = function (event, matchedEl, container) { if (Dom.hasClass(matchedEl, "selected")) { Dom.removeClass(matchedEl, "selected"); } else { Dom.addClass(matchedEl, "selected"); } }; // Use the "delegate" method to attach a "click" event listener to the // container (<div id="container">). The listener will only be called if the // target of the click event matches the element specified via the CSS // selector passed as the fourth argument to the delegate method. Event.delegate("container", "click", onLIClick, "li"); })();

The same technique works for the `mouseover` and `mouseout` events as well.

(function() { var Dom = YAHOO.util.Dom, Event = YAHOO.util.Event; var onLIMouseOver = function (event, matchedEl, container) { Dom.addClass(matchedEl, "hover"); }; var onLIMouseOut = function (event, matchedEl, container) { Dom.removeClass(matchedEl, "hover"); }; // Use the "delegate" method to attach a mouseover and mouseout event listener // to the container (<div id="container">). The listener will only be called // if the target of the click event matches the element specified via the CSS // selector passed as the fourth argument to the delegate method. Event.delegate("container", "mouseover", onLIMouseOver, "li"); Event.delegate("container", "mouseout", onLIMouseOut, "li"); })();

In this example, we've used three event listeners with their associated memory and performance load to serve as delegates for the same three events on each item in the list. Instead of 3 event listeners per item, we now have three on the container. And the code works regardless of the number of `li`'s added to the list — if the list was 100 items long, we'd be saving ourselves 297 event listeners, which is enough to make a noticable difference in how your page responds. In a complicated page context, it's easy to see how this technique can dramatically reduce the number of event listeners required and thereby improve the performance of your application.

## Configuration for This Example

You can load the necessary JavaScript and CSS for this example from Yahoo's servers. Click here to load the YUI Dependency Configurator with all of this example's dependencies preconfigured.

### YUI Logger Output:

Note: You are viewing this example in debug mode with logging enabled. This can significantly slow performance.

Reload with logging
and debugging disabled.

### Event Utility Examples:

- Simple Event Handling and Processing
- Using Custom Events
- Using onAvailable, onContentReady, and onDOMReady
- Using Event Utility and Event Delegation to Improve Performance
- Skinning via Progressive Enhancement using the Event Utility and the YUILoader
- Implementing Container Keyboard Shortcuts with KeyListener (included with examples for Container Family)
- Using the Container ARIA Plugin (included with examples for Container Family)

### More Event Utility Resources:

- User's Guide (external)
- API Documentation
- Cheat Sheet PDF (external)

Copyright © 2009 Yahoo! Inc. All rights reserved.

Privacy Policy - Terms of Service - Copyright Policy - Job Openings