Yahoo! Developer Network Home - Help

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 or clicking on the list items will report their ID attributes in the Logger window on the right side of the screen. Because we're using event delegation, only one event listener is needed for each type of event (`click` and `mouseover`) to handle the event response for `n` list items. Even if there were 100 list items, we'd still just need one event handler per event type.

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

## Event Delegation and the YUI Event Utility

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 both `click` and `mouseover` events. The problem we will solve here involves reacting to `click` and `mouseover` events on list items. We will assume that there can be many list items and that 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` or `mouseover` 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:

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 6 `<li>` children. Note that our list items have ID attributes — this gives us a way to uniquely identify them when we process `click`s and `mouseover`s at the container level.

<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> <li id="li-6">List Item 6</li> </ul> </div>

We'll use the YUI Logger Control as the reporting mechanism for our event handlers, so this example begins its script by creating a LogReader instance and rendering it into the document body when the `window`'s `load` event fires:

//create log reader instance on pageload function loggerInit() { var myLogReader = new YAHOO.widget.LogReader(); } //on is an alias for addListener YAHOO.util.Event.on(window, "load", loggerInit);

Now we'll add an event handler to the container `<div>`, listening for any clicks within its bounds. We're only really interested in clicks on `<li>`s, though; when we get one of those, we'll write out a message to the Logger.

function clickHandler(e) { //get the resolved (non-text node) target: var elTarget = YAHOO.util.Event.getTarget(e); //walk up the DOM tree looking for an <li> //in the target's ancestry; desist when you //reach the container div while (elTarget.id != "container") { //are you an li? if(elTarget.nodeName.toUpperCase() == "LI") { //yes, an li: so write out a message to the log YAHOO.log("The clicked li had an id of " + elTarget.id, "info", "clickExample"); //and then stop looking: break; } else { //wasn't the container, but wasn't an li; so //let's step up the DOM and keep looking: elTarget = elTarget.parentNode; } } } //attach clickHandler as a listener for any click on //the container div: YAHOO.util.Event.on("container", "click", clickHandler);

The same technique works for the `mousemove` event as well. We'll substitute `mousemove` for `click`, but make no other substantive changes:

function mouseHandler(e) { var elTarget = YAHOO.util.Event.getTarget(e); while (elTarget.id != "container") { if(elTarget.nodeName.toUpperCase() == "LI") { YAHOO.log("The li that was mousedover had an id of " + elTarget.id, "info", "mouseExample"); break; } else { elTarget = elTarget.parentNode; } } } YAHOO.util.Event.on("container", "mouseover", mouseHandler);

In this example, we've used two event listeners with their associated memory and performance load to serve as delegates for the same two events on six list items. Instead of 12 event listeners, we now have two. And the code works regardless of the number of `li`'s used — if the list was 100 items long, we'd be saving ourselves 198 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.

### YUI Logger Output:

### Event Utility Examples:

### More Event Utility Resources:

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

Copyright © 2008 Yahoo! Inc. All rights reserved.

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