YUI 3: Event

YUI's Event Utility facilitates the creation of event-driven applications in the browser by giving you a simplified interface for responding to DOM events. The Event Utility package also includes the Custom Event object; Custom Events allow you to publish the interesting moments or events in your own code so that other components on the page can subscribe to those events and respond to them.

The Event Utility package provides the following features:

  • DOM event handling
  • Automatic deferral of handler attachment for elements that are not yet available
  • Automatic scope correction, optional scope assignment
  • An event facade that normalizes browser differences
  • Automatic DOM event listener cleanup
  • Simulation of events in all A-grade browsers
  • Pageload timing events (available and contentready at the element level and domready at the DOM level)
  • Keylistener utility that responds only when certain key combinations are detected.
  • Focus/blur event abstraction layer that provides the ability to use deletegated listening techniques with these events.
  • Custom events that are bubbleable, cancelable, and have intrinsic AOP qualities

YUI Theater: Luke Smith — Events Evolved

YUI engineer Luke Smith provides a deep introduction to the YUI 3 event system including its support for DOM events, event delegation, synthetic events, and custom events.

[More Videos | Transcript]

Getting Started

Include Dependencies

The easiest way to include the source files for Event and its dependencies is to add the YUI seed file to your page, using the following script tag, and allow the YUI instance to download any additional files which may be required:

  1. <script src="http://yui.yahooapis.com/3.0.0/build/yui/yui-min.js"></script>
<script src="http://yui.yahooapis.com/3.0.0/build/yui/yui-min.js"></script>

The YUI instance will automatically pull down Event's source files and any missing dependencies when the event module is used. This helps you avoid having to manually manage the list of files needed on your page to support multiple components while also optimizing your initial page weight by loading files only when they are required.

If you do want to include file dependencies manually on your page, the YUI Dependency Configurator can be used to determine the list of files you need to include in order to use Event.

The YUI Instance

Once you have the YUI seed file on your page (yui-min.js), you can create a new YUI instance for your application to use and populate it with the modules you need, specified as the first set of arguments to the use method:

  1. // Create new YUI instance, and populate it with the required modules
  2. YUI().use('event', function(Y) {
  3.  
  4. // Event available, and ready for use.
  5.  
  6. });
// Create new YUI instance, and populate it with the required modules
YUI().use('event', function(Y) {
 
    // Event available, and ready for use.
 
});

The last argument passed to use is a callback function. The callback function will be invoked as soon as the YUI instance is done downloading any required files missing from your page. Once those files are loaded, your local YUI instance will be supplemented with the classes which make up the event module and any modules it depends on. A reference to the populated YUI instance (Y) is passed back to your callback function. Within your callback, then, you can start writing your application code based on your own custom instance of YUI.

For more information on creating instances of YUI and the use method, see the YUI Global object documentation.

DOM Events

To attach an event handler to the DOM, simply define your event handler and pass the event handler to the Event Utility along with a reference to the event for which you want to listen and the element to which you want attach the handler:

  1. //the function we'll use to handle the event:
  2. function handleClick(e) {
  3. //Pass the event facade to the logger or console for
  4. //inspection:
  5. Y.log(e);
  6. }
  7.  
  8. //assuming we have an element on the page with an ID
  9. //attribute "foo":
  10. YUI().use('node-base', function(Y) {
  11. Y.on("click", handleClick, "#foo");
  12. });
//the function we'll use to handle the event:
function handleClick(e) {
	//Pass the event facade to the logger or console for
    //inspection:
    Y.log(e);
}
 
//assuming we have an element on the page with an ID
//attribute "foo":
YUI().use('node-base', function(Y) {
    Y.on("click", handleClick, "#foo");
});

These lines of code:

  • Create a YUI instance — Event Utility relies on node-base, so YUI().use("node-base") will load everything required to use the core features of the event utility. The functionality is identical if you ask for 'event-base' instead. Several 'special' event implementations are bundled as submodules. These are not included in event-base. These special events are described below, and can be included by using the name of the submodule that contains the functionality, or by using event, which is a rollup containing all of the DOM Event functionality.
  • Define a callback function, handleClick(e), to handle the specified event.
  • Call the on method on the YUI instance (Y) to bind an event to the DOM element. The on method requires three arguments: the event to bind ("click", as a string), the callback function (handleClick), and the element the event is bound to ("#foo", assuming an element whose ID attribute is foo).

Because we are identifying the element by its HTML ID ("#foo" as a string) rather than by passing in a Node instance or a direct HTMLElement reference, it is possible to refer to an element that does not yet exist on the page. The Event Utility attempts to find the DOM element by its id value; should it fail to find the element immediately, it continues to seek the element for up to 15 seconds after the page has loaded. This "automatic deferral" enables you, in some cases, to write your event attachment code directly into your script rather than separating it out in a function that runs only after the page has loaded.

To attach an event handler to multiple elements, use CSS selector syntax (as above) that selects multiple elements, pass in multiple selector strings as an array, pass in an array of Node instances, or pass in an array of direct element references:

  1. YUI().use('node-base', function(Y) {
  2.  
  3. //elements can be targeted using selector syntax:
  4. Y.on("click", handleClick, "#foo p"); //targets all p elements that are descendants
  5. //of #foo
  6.  
  7. //elements can be targeted by Node references:
  8. var foo = Y.one("#foo");
  9. Y.on("click", handleClick, foo);
  10. foo.on("click", handleClick); //same as above
  11.  
  12. //elements can be passed in as direct references:
  13. var foo = document.getElementById("foo");
  14. Y.on("click", handleClick, foo);
  15.  
  16. //In all cases, you can pass in an array instead of a
  17. //single item:
  18. Y.on("click", handleClick, ["#foo p", "#bar"]);
  19. });
YUI().use('node-base', function(Y) {
 
    //elements can be targeted using selector syntax:
    Y.on("click", handleClick, "#foo p"); //targets all p elements that are descendants
                                          //of #foo
 
    //elements can be targeted by Node references:
    var foo = Y.one("#foo");
    Y.on("click", handleClick, foo);
    foo.on("click", handleClick); //same as above
 
    //elements can be passed in as direct references:
    var foo = document.getElementById("foo");
    Y.on("click", handleClick, foo);
 
    //In all cases, you can pass in an array instead of a
    //single item:
    Y.on("click", handleClick, ["#foo p", "#bar"]);
});

Using on: Controlling Context and Arguments

When you call Y.on, you have the following arguments to work with:

  1. Event name: This is the string reference to the DOM event to which you want to respond (e.g., "click" or "mouseover"). Developers often wonder where they can find a comprehensive list of DOM events that shows in which browsers each event is supported. As far as we know, no perfect list exists. Danny Goodman's DHTML: The Definitive Reference may have the most comprehensive information of this kind; PPK's Event Compatibility Table on quirksmode may have the best compatibility assessment online. The Event Utility does not place any constraints on the events for which you attach handlers; it will attempt to attach listeners for any event name you provide. It's your responsibility to make sure that the event you're using is one that is supported in the browsers for which you're developing.
  2. Handler: A reference to the function that should be called when the specified event takes place.
  3. Element(s): As noted above, this can be one or more elements referenced using selector syntax, Node instances, or direct element references.
  4. Context object: A reference to the object that will provide the context for the event handler — the object to which this will refer when the handler executes. If this is omitted, the context object will be a Node instance based on the target element.
  5. Argument 1 ... n: The fifth thru nth arguments passed to on will be passed to the event handler.

The following code shows these arguments in use. HTML:

  1. <div id="list">
  2. <ul>
  3. <li id="one" class="odd">Item one</li>
  4. <li id="two" class="even">Item two</li>
  5. <li id="three" class="odd">Item three</li>
  6. <li id="four" class="even">Item four</li>
  7. </ul>
  8. </div>
<div id="list">
    <ul>
        <li id="one" class="odd">Item one</li>
        <li id="two" class="even">Item two</li>
        <li id="three" class="odd">Item three</li>
        <li id="four" class="even">Item four</li>
    </ul>
</div>

Script:

  1. //Create YUI instance:
  2. YUI().use("dump", "node-base", function(Y) {
  3.  
  4. //create arbitrary context object:
  5. var contextObj = {
  6. name: "context"
  7. };
  8.  
  9. //function to handle click events and report information about them:
  10. function handleClick(e, arg1, arg2) {
  11. Y.log("Context object:" + Y.dump(this));
  12. Y.log("Event facade object:" + Y.dump(e));
  13. Y.log(arguments);
  14. }
  15.  
  16. //subscribe odd numbered list items to the click event
  17. Y.on("click", handleClick, "#list .odd", contextObj, "argumentOne", "argumentTwo");
  18. });
//Create YUI instance:
YUI().use("dump", "node-base", function(Y) {
 
    //create arbitrary context object:
    var contextObj = {
        name: "context"
    };
 
    //function to handle click events and report information about them:
    function handleClick(e, arg1, arg2) {
        Y.log("Context object:" + Y.dump(this));
        Y.log("Event facade object:" + Y.dump(e));
        Y.log(arguments);
    }
 
    //subscribe odd numbered list items to the click event
    Y.on("click", handleClick, "#list .odd", contextObj, "argumentOne", "argumentTwo");
});

When you run this code and click on "Item one" or "Item three", the following information will be sent to Y.log:

  1. Context object: {name => context}
  2. Event facade object: {
  3. altKey => false,
  4. cancelBubble => false,
  5. ctrlKey => false,
  6. //and remaining event facade properties
  7. ...}
Context object: {name => context}
Event facade object: {
	altKey => false, 
    cancelBubble => false, 
    ctrlKey => false, 
    //and remaining event facade properties
    ...}

The final object logged, the arguments object, will contain three items: e (the event facade), "argumentOne" (string), and "argumentTwo" (string).

Legacy Methods: Event.addListener and Event.on

The Event Utility contains two legacy methods for attaching event listeners; these are located in the Event package and follow the syntax of the Event Utility from previous versions of YUI. If you are writing code using YUI 3.x, you should avoid using these methods and instead use the syntax described above.

Removing Events

There are three ways to remove an event listener:

  1. Add an event category prefix to the event type parameter, and pass this string to the YUI detach method.
  2. Call detach on the event's handle: The return value of on is an event handle object; that object contains a detach method that can be used to remove the event.
  3. Call the YUI detach method, passing in event type, handler, and element: detach is available as a method on your YUI instance and can be used when you don't have access to the event handle.

Sample code for each of these methods:

  1. //Get a YUI instance:
  2. YUI().use('node-base', function(Y) {
  3.  
  4. //an event handler:
  5. function handleClick(e) {
  6. Y.log(e);
  7. }
  8.  
  9. // attach a click event handler to element foo. The 'eventcategory|'
  10. // part of this is an optional string that can be used to detach
  11. // the listener
  12. var fooHandle = Y.on("eventcatgory|click", handleClick, "#foo");
  13.  
  14. // detach by event category prefix
  15. Y.detach('eventcategory|click');
  16.  
  17. // detach the handler using the handle:
  18. fooHandle.detach();
  19.  
  20. // detach all listeners filed under the 'eventcategory' category
  21. Y.detach('eventcategory|*');
  22.  
  23. // detach the handler via detach:
  24. Y.detach("click", handleClick, "#foo");
  25.  
  26. // or pass the event handle to detach:
  27. Y.detach(fooHandle);
  28. });
//Get a YUI instance:
YUI().use('node-base', function(Y) {
 
    //an event handler:
    function handleClick(e) {
        Y.log(e);
    }
 
    // attach a click event handler to element foo.  The 'eventcategory|'
    // part of this is an optional string that can be used to detach
    // the listener
    var fooHandle = Y.on("eventcatgory|click", handleClick, "#foo");
 
    // detach by event category prefix
    Y.detach('eventcategory|click');
 
    // detach the handler using the handle:
    fooHandle.detach();
 
    // detach all listeners filed under the 'eventcategory' category
    Y.detach('eventcategory|*');
 
    // detach the handler via detach:
    Y.detach("click", handleClick, "#foo");
 
    // or pass the event handle to detach:
    Y.detach(fooHandle);
});

Event.purgeElement lets you remove all DOM event listeners that were registered via on from an element. Optionally, a specific type of listener can be specified. In addition, the element's children can also be purged.

  1. //get a YUI instance:
  2. YUI().use('node-base', function(Y) {
  3. // purge all listeners:
  4. Y.Event.purgeElement("#foo");
  5. // all listeners and recurse children:
  6. Y.Event.purgeElement("#foo", true);
  7. // only click listeners, and don't recurse:
  8. Y.Event.purgeElement("#foo", false, "click");
  9. });
//get a YUI instance:
YUI().use('node-base', function(Y) {
    // purge all listeners:
    Y.Event.purgeElement("#foo");
    // all listeners and recurse children:
    Y.Event.purgeElement("#foo", true);
    // only click listeners, and don't recurse:
    Y.Event.purgeElement("#foo", false, "click");
});

Simulating Events

Simulated events are browser-created events that, most of the time, behave exactly as user-initated events. Events bubble as they normally would and event objects are created with properties containing data about the event (sometimes these properties are browser-specific, so it's recommended that you make use of the browser-equalizing methods of Y.Event to retrieve the appropriate values for properties such as target, relatedTarget, and charCode. All event handlers are called synchronously at each event target throughout the event's lifetime. Events are simulated using the simulate() method on any Y.Node instance.

Mouse Events

There are seven mouse events that can be simulated:

  • click
  • dblclick
  • mousedown
  • mouseup
  • mouseover
  • mouseout
  • mousemove

Each event is fired by calling simulate() and passing in two arguments: the type of event to fire and an optional object specifying additional information for the event. To simulate a click on the document's body element, for example, the following code can be used:

  1. //get a YUI instance:
  2. YUI().use('node-event-simulate', function(Y) {
  3.  
  4. Y.one("body").simulate("click");
  5. });
  6.  
//get a YUI instance:
YUI().use('node-event-simulate', function(Y) {
 
    Y.one("body").simulate("click");
});
 

This code simulates a click with all of the default properties on the event object. To specify additional information, such as the Shift key being down, the second argument must be used and the exact DOM name for the event property specified (there is browser-normalizing logic that translates these into browser-specific properties when necessary):

  1. YUI().use('node-event-simulate', function(Y) {
  2.  
  3. Y.one("body").simulate("click", { shiftKey: true });
  4. });
YUI().use('node-event-simulate', function(Y) {
 
    Y.one("body").simulate("click", { shiftKey: true });
});

In this updated example, a click event is fired on the document's body while simulating that the Shift key is down.

The extra properties to specify vary depending on the event being simulated and are limited to this list:

  • detail - Indicates the number of times a button was clicked (DOM-compliant browsers only).
  • screenX/screenY - coordinates of the mouse event in relation to the entire screen (DOM-compliant browsers only).
  • clientX/clientY - coordinates of the mouse event in relation to the browser client area.
  • ctrlKey/altKey/shiftKey/metaKey - the state of the Ctrl, Alt, Shift, and Meta keys, respectively (true for down, false for up).
  • button - the button being used for the event, 0 for left (default), 1 for right, 2 for center.
  • relatedTarget - the element the mouse moved from (during a mouseover event) or to (during a mouseout event).

Examples of the different methods and their extra properties:

  1. YUI().use('node-event-simulate', function(Y) {
  2.  
  3. var node = Y.one("#myDiv");
  4.  
  5. //simulate a click Alt key down
  6. node.simulate("click", { altKey: true});
  7.  
  8. //simulate a double click with Ctrl key down
  9. node.simulate("dblclick", { ctrlKey: true });
  10.  
  11. //simulate a mouse over
  12. node.simulate("mouseover", { relatedTarget: document.body });
  13.  
  14. //simulate a mouse out
  15. node.simulate("mouseout", { relatedTarget: document.body });
  16.  
  17. //simulate a mouse down at point (100,100) in the client area
  18. node.simulate("mousedown", { clientX: 100, clientY: 100 });
  19.  
  20. //simulate a mouse up at point (100,100) in the client area
  21. node.simulate("mouseup", { clientX: 100, clientY: 100 });
  22.  
  23. //simulate a mouse move at point (200, 200) in the client area
  24. node.simulate("mousemove", { clientX: 200, clientY: 200 });
  25. });
  26.  
YUI().use('node-event-simulate', function(Y) {
 
    var node = Y.one("#myDiv");
 
    //simulate a click Alt key down
    node.simulate("click", { altKey: true});
 
    //simulate a double click with Ctrl key down
    node.simulate("dblclick", { ctrlKey: true });
 
    //simulate a mouse over
    node.simulate("mouseover", { relatedTarget: document.body });
 
    //simulate a mouse out
    node.simulate("mouseout", { relatedTarget: document.body });
 
    //simulate a mouse down at point (100,100) in the client area
    node.simulate("mousedown", { clientX: 100, clientY: 100 });
 
    //simulate a mouse up at point (100,100) in the client area
    node.simulate("mouseup", { clientX: 100, clientY: 100 });
 
    //simulate a mouse move at point (200, 200) in the client area
    node.simulate("mousemove", { clientX: 200, clientY: 200 });
});
 

Key Events

There are three key event simulations available:

  • keyup
  • keydown
  • keypress

As with the mouse events, key events are simulated using simulate(). For keyup and keydown, the keyCode property must be specified; for keypress, the charCode property must be included. In many cases, keyCode and charCode may be the same value to represent the same key (97, for instance, represents the "A" key as well as being the ASCII code for the letter "a"). For example:

  1. YUI().use('node-event-simulate', function(Y) {
  2.  
  3. var node = Y.one("#myDiv");
  4.  
  5. //simulate a keydown on the A key
  6. node.simulate("keydown", { keyCode: 97 });
  7.  
  8. //simulate a keyup on the A key
  9. node.simulate("keyup", { keyCode: 97 });
  10.  
  11. //simulate typing "a"
  12. node.simulate("keypress", { charCode: 97 });
  13. });
YUI().use('node-event-simulate', function(Y) {
 
    var node = Y.one("#myDiv");
 
    //simulate a keydown on the A key
    node.simulate("keydown", { keyCode: 97 });
 
    //simulate a keyup on the A key
    node.simulate("keyup", { keyCode: 97 });
 
    //simulate typing "a"
    node.simulate("keypress", { charCode: 97 });    
});

Key events also support the ctrlKey, altKey, shiftKey, and metaKey event properties.

Note: Due to differences in browser implementations, key events may not be simulated in the same manner across all browsers. For instance, when simulating a keypress event on a textbox, only Firefox will update the textbox with the new character of the key that was simulated to be pressed. For other browsers, the events are still registered and all event handlers are called, however, the textbox display and value property are not updated. These differences should go away as browser support for simulated events improves in the future.

Using the available and contentready events (Formerly the onAvailable and onContentReady methods)

available lets you define a function that will execute as soon as an element is detected in the DOM. The intent is to reduce the occurrence of timing issues when rendering script and html inline. It is not meant to be used to define handlers for elements that may eventually be in the document; it is meant to be used to detect elements you are in the process of loading.

The argument signature for available is illustrated here:

  1. YUI().use('node-base', function(Y) {
  2.  
  3. function TestObj(id) {
  4. Y.on('available', this.handleOnAvailable, id, this);
  5. }
  6.  
  7. TestObj.prototype.handleOnAvailable = function(me) {
  8. Y.log(this.id + " is available");
  9. }
  10.  
  11. var obj = new TestObj("myelementid");
  12. });
  13.  
YUI().use('node-base', function(Y) {
 
    function TestObj(id) {
      Y.on('available', this.handleOnAvailable, id, this); 
    }
 
    TestObj.prototype.handleOnAvailable = function(me) {
      Y.log(this.id + " is available");
    }
 
    var obj = new TestObj("myelementid");
});
 
  1. <div id="myelementid">my element</div>
  2.  
 <div id="myelementid">my element</div>
 

The contentready method shares an identical syntax with available. The material difference between the two methods is that contentready waits until both the target element and its nextSibling in the DOM respond to getElementById. This guarantees that the target element's contents will have loaded fully (excepting any dynamic content you might add later via script). If contentready never detects a nextSibling, it fires with the window.load event.

Using the domready Event (Formerly onDOMReady)

The domready custom event lets you define a function that will execute as soon as the DOM is in a usable state. The DOM is not deemed "usable" until it is structurally complete; a number of bugs, primarily in IE, can lead to the browser crashing or failing to load the page successfully if scripts attempt to insert information into the DOM prior to the DOM being in a complete state.

DOM readiness is achieved before images have finished loading, however, so domready is often an excellent alternative to using the window object's load event.

  1. YUI().use('node-base', function(Y) {
  2. function init() {
  3. Y.one("#hidden_element").set("visibility", "");
  4. }
  5. Y.on("domready", init);
  6.  
  7. // As with all custom events, you can pass
  8. // a context object and arguments that will be
  9. // passed to your handlers:
  10. // Y.on("domready", init, contexObject, argumentOne, argumentTwo, argumentN);
  11. });
  12.  
YUI().use('node-base', function(Y) {
     function init() {
        Y.one("#hidden_element").set("visibility", "");
     }
     Y.on("domready", init);
 
     // As with all custom events, you can pass
     // a context object and arguments that will be
     // passed to your handlers:
     // Y.on("domready", init, contexObject, argumentOne, argumentTwo, argumentN);
});
 

Using the key Event

The key event lets you define a function that will execute only when a certain key (or set of keys), with or without modifiers, is detected.

Creating a Key Listener

The following will attach a keydown listener to an element with the id of 'text1'. The listener will only be exectued if the return key (keyCode 13) is detected, and the listener is removed the first time this key is detected.

  1. YUI().use('event-key', function(Y) {
  2.  
  3. // store the return value from Y.on to remove the listener later
  4. var handle = Y.on('key', function(e, arg1, arg2, etc) {
  5. Y.log(e.type + ": " + e.keyCode + ' -- ' + arg1);
  6.  
  7. // stopPropagation() and preventDefault()
  8. e.halt();
  9.  
  10. // unsubscribe so this only happens once
  11. handle.detach();
  12.  
  13. // Attach to 'text1', specify keydown, keyCode 13, make Y the context, add arguments
  14. }, '#text1', 'down:13', Y, "arg1", "arg2", "etc");
  15.  
  16. });
  17.  
YUI().use('event-key', function(Y) {
 
    // store the return value from Y.on to remove the listener later
    var handle = Y.on('key', function(e, arg1, arg2, etc) {
        Y.log(e.type + ": " + e.keyCode + ' -- ' + arg1);
 
        // stopPropagation() and preventDefault()
        e.halt();
 
        // unsubscribe so this only happens once
        handle.detach();
 
    // Attach to 'text1', specify keydown, keyCode 13, make Y the context, add arguments
    }, '#text1', 'down:13', Y, "arg1", "arg2", "etc");
 
});
 

Defining a Key Listener Specification

In the previous example, 'down:13' was provided as the key listener specification. This specifies that the listener should only fire if the return key triggers a keydown event. The specification string consists of three parts:

  1. The key event type followed by a colon ('up:', 'down:, or 'press:')
  2. zero or more keyCodes to listen for, separated by commas. If more than one keyCode is specified, the listener will fire if any of the codes are detected. ('up:12,13,14')
  3. zero or more modifiers keys to listen for, separated by the plus symbol. If modifiers are specified, all must be detected in order for the listener to fire ('+shift+ctrl+alt+meta').

So, the following specification will fire only if keyCode 65 or 66 is detected during a keypress event while shift and control are held down: 'press:65,66+shift+ctrl'

Using the delegate Method

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

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.

Creating A Delegated Event Listener

Consider the following HTML.

  1. <div id="container">
  2. <ul>
  3. <li id="item-1"><em>Item Type One</em></li>
  4. <li id="item-2"><em>Item Type Two</em></li>
  5. <li id="item-3"><em>Item Type Three</em></li>
  6. </ul>
  7. </div>
  8.  
<div id="container">
    <ul>
        <li id="item-1"><em>Item Type One</em></li>
        <li id="item-2"><em>Item Type Two</em></li>
        <li id="item-3"><em>Item Type Three</em></li>
    </ul>
</div>
 

Using Y.delegate, pass the name of the event to delegate as the first argument, followed by the listener to be called, the Node serving as the delegation container (the Node to which the listener is to be attached), and finally a CSS selector used to define the descendant Nodes that must match the target of the event in order for the listener to be called.

The following example will bind a single click event listener to the container (<div id="container">) but that listener will only be called if the target of the event is an <li>.

  1. YUI().use("event-delegate", function(Y) {
  2.  
  3. Y.delegate("click", function(e) {
  4.  
  5. // The list item that matched the provided selector is the
  6. // default scope
  7. Y.log("Default scope: " + this.get("id"));
  8.  
  9. // The list item that matched the provided selector is
  10. // also available via the event's currentTarget property
  11. // in case the default scope is changed.
  12. Y.log("Clicked list item: " + e.currentTarget.get("id"));
  13.  
  14. // The actual click target, which could be the matched item or a
  15. // descendant of it.
  16. Y.log("Event target: " + e.target);
  17.  
  18. // The delegation container is passed as a third argument
  19. Y.log("Delegation container: " + e.container.get("id"));
  20.  
  21.  
  22. }, "#container", "li");
  23.  
  24. });
  25.  
YUI().use("event-delegate", function(Y) {
 
	Y.delegate("click", function(e) {
 
		//	The list item that matched the provided selector is the 
		//	default scope
		Y.log("Default scope: " + this.get("id"));
 
		//	The list item that matched the provided selector is 
		//	also available via the event's currentTarget property
		//	in case the default scope is changed.
		Y.log("Clicked list item: " + e.currentTarget.get("id"));
 
	    //	The actual click target, which could be the matched item or a
	    //	descendant of it.
		Y.log("Event target: " + e.target);	
 
		//	The delegation container is passed as a third argument
		Y.log("Delegation container: " + e.container.get("id"));	
 
 
	}, "#container", "li");
 
});
 

Using the focus and blur Events

Since the DOM focus and blur events do not bubble, use the Event Utility's focus and blur events as an alternative to attaching discrete DOM focus and blur event handlers to focusable elements. The focus and blur events leverage capture-phase DOM event listeners (focusin and focusout for IE), making it possible to attach a single listener to an element and listen for the focus and blur events fired by all its focusable descendants. As reducing the number of event listeners is a proven strategy for improving performance, using the focus and blur events is a great way to help speed up any page or application that requires listening for either event.

Creating a focus Listener

Consider the following HTML.

  1. <div id="toolbar">
  2. <input type="button" id="button-cut" name="button-cut" value="Cut">
  3. <input type="button" id="button-copy" name="button-copy" value="Copy">
  4. <input type="button" id="button-paste" name="button-paste" value="Paste">
  5. </div>
  6.  
<div id="toolbar">
    <input type="button" id="button-cut" name="button-cut" value="Cut">
    <input type="button" id="button-copy" name="button-copy" value="Copy">
    <input type="button" id="button-paste" name="button-paste" value="Paste">
</div>
 

Listening for the focus event for every button in the toolbar would typically require attaching discrete event listeners to each button. However, using the Event Utility it is possible to attach a single listener to the containing element (in this case <div id="toolbar">) and be notified when each button is focused.

  1. YUI().use("event-focus", function(Y) {
  2.  
  3. var handle = Y.on("focus", function(e, arg1, arg2, etc) {
  4.  
  5. Y.log("target: " + e.target + ", arguments: " + arg1 + ", " + arg2 + ", " + etc);
  6.  
  7. // Attach to the element with the id of "toolbar", make Y the context, add arguments
  8. }, "#toolbar", Y, "arg1", "arg2", "etc");
  9.  
  10. });
  11.  
YUI().use("event-focus", function(Y) {
 
    var handle = Y.on("focus", function(e, arg1, arg2, etc) {
 
		Y.log("target: " + e.target + ", arguments: " + arg1 + ", " + arg2 + ", " + etc);
 
    // Attach to the element with the id of "toolbar", make Y the context, add arguments
    }, "#toolbar", Y, "arg1", "arg2", "etc");
 
});
 

Using the mouseenter and mouseleave Events

Inspired by Internet Explorer's mouseenter and mouseleave events, the Event Utility offers the ability to listen for the mouseenter and mouseleave events in all A-Grade Browsers. For DOM operations executed in response to mouseover and mouseout, using mouseenter and mouseleave can be performance-boosting alternatives in that since they don't bubble, the changes to the DOM will be made less frequently.

Creating a mouseenter Listener

Consider the following HTML.

  1. <div id="container">
  2. <ul>
  3. <li><em>Item Type One</em></li>
  4. <li><em>Item Type Two</em></li>
  5. <li><em>Item Type Three</em></li>
  6. </ul>
  7. </div>
  8.  
<div id="container">
    <ul>
        <li><em>Item Type One</em></li>
        <li><em>Item Type Two</em></li>
        <li><em>Item Type Three</em></li>
    </ul>
</div>
 

The following will attach a mouseenter and mouseleave listener to the list's container (<div id="container">). The mouseenter listener will be called once—the first time the mouse enters the container. The mouseleave listener will be called once as well—the first time the mouse leaves the container.

  1. YUI().use("event-mouseenter", function(Y) {
  2.  
  3. Y.on("mouseenter", function (e) {
  4.  
  5. Y.log("Mouse entered: " + this.get("id"));
  6.  
  7. }, "#container");
  8.  
  9. Y.on("mouseleave", function (e) {
  10.  
  11. Y.log("Mouse left: " + this.get("id"));
  12.  
  13. }, "#container");
  14.  
  15. });
  16.  
YUI().use("event-mouseenter", function(Y) {
 
	Y.on("mouseenter", function (e) {
 
		Y.log("Mouse entered: " + this.get("id"));
 
	}, "#container");
 
	Y.on("mouseleave", function (e) {
 
		Y.log("Mouse left: " + this.get("id"));
 
	}, "#container");
 
});
 

Using Custom Events

The YUI Custom Event System enables you to define and use events beyond those available in the DOM — events that are specific to and of interest in your own application. Custom Events are designed to work much like DOM events. They can bubble, pass event facades, have their propagation and default behaviors suppressed, etc. This section describes several common uses of YUI Custom Events and provides some sample code. It contains these sections:

Simple Custom Events Using Y.on

You can send out notification of an interesting moment anywhere from your code simply by calling your yui instance's fire method.

  1. //Create a YUI instance:
  2. YUI().use('event-custom', function(Y) {
  3. Y.fire('customapp:started', 1, 2, 3);
  4. });
  5.  
//Create a YUI instance:
YUI().use('event-custom', function(Y) {
    Y.fire('customapp:started', 1, 2, 3);
});
 

This will send out notifications to any function that previously subscribed to that event:

  1. Y.on('customapp:started', function(arg1, arg2, arg3) {
  2. Y.log('Custom App Started, now I can do a a few things);
  3. // the arguments 1, 2, and 3 were provided by fire()
  4. });
  5.  
Y.on('customapp:started', function(arg1, arg2, arg3) {
    Y.log('Custom App Started, now I can do a a few things);
    // the arguments 1, 2, and 3 were provided by fire()
});

Defining a Custom Event on an Event Target

A common way to create a Custom Event is to augment an object with EventTarget, making it able to host Custom Events and be a target for Custom Events that are bubbling from other hosts:

  1. YUI().use('event-custom', function(Y) {
  2.  
  3. // define a constructor:
  4. function Publisher() {
  5. // create a custom event. it is not necessary to explicitly publish an event
  6. // unless you need to override the default configuration
  7. this.publish("publisher:testEvent", {
  8. // configuration options for this event
  9. });
  10. }
  11. // augment the Publisher with EventTarget:
  12. Y.augment(Publisher, Y.EventTarget, null, null, {
  13. // this argument is provided to EventTarget's constructor, and
  14. // lets you set up default configuration values for every event
  15. // published on this event target.
  16. });
  17.  
  18. // if you accept the default configuration, augmenting EventTarget looks like this:
  19. // Y.augment(Publisher, Y.EventTarget);
  20. });
  21.  
YUI().use('event-custom', function(Y) {
 
    // define a constructor:
    function Publisher() {
        // create a custom event.  it is not necessary to explicitly publish an event
        // unless you need to override the default configuration
        this.publish("publisher:testEvent", {
            // configuration options for this event
        });
    }
    // augment the Publisher with EventTarget:
    Y.augment(Publisher, Y.EventTarget, null, null, {
        // this argument is provided to EventTarget's constructor, and
        // lets you set up default configuration values for every event
        // published on this event target.
    });
 
    // if you accept the default configuration, augmenting EventTarget looks like this:
    // Y.augment(Publisher, Y.EventTarget);
});
 

The publish constructor creates a new Custom Event. It takes one required parameter and one optional parameter:

  • type — The type of event. This string is returned to listeners that receive this event so that they know what event occurred.
  • options — The specific configuration options you want to define for this Custom Event. Most properties of the Custom Event class can be set at this time.

Subscribing (Listening) to a Custom Event

To subscribe to a custom event, use its on method. Following the code above, you would subscribe to the publisher:testEvent as follows:

  1. var publisher = new Publisher();
  2. publisher.on("publisher:testEvent", function(e) {
  3. //event handler code
  4. });
  5.  
var publisher = new Publisher();
publisher.on("publisher:testEvent", function(e) {
    //event handler code
});
 

Firing the Event

To trigger or fire a custom event, simpy call its fire method:

  1. publisher.fire("publisher:testEvent");
  2.  
publisher.fire("publisher:testEvent");
 

YUI on Mobile: Using Event Utility with "A-Grade" Mobile Browsers

About this Section: YUI generally works well with mobile browsers that are based on A-Grade browser foundations. For example, Nokia's N-series phones, including the N95, use a browser based on Webkit — the same foundation shared by Apple's Safari browser, which is found on the iPhone. The fundamental challenges in developing for this emerging class of full, A-Grade-derived browsers on handheld devices are:

  • Screen size: You have a much smaller canvas;
  • Input devices: Mobile devices generally do not have mouse input, and therefore are missing some or all mouse events (like mouseover);
  • Processor power: Mobile devices have slower processors that can more easily be saturated by JavaScript and DOM interactions — and processor usage affects things like battery life in ways that don't have analogues in desktop browsers;
  • Latency: Most mobile devices have a much higher latency on the network than do terrestrially networked PCs; this can make pages with many script, css or other types of external files load much more slowly.

There are other considerations, many of them device/browser specific (for example, current versions of the iPhone's Safari browser do not support Flash). The goal of these sections on YUI User's Guides is to provide you some preliminary insights about how specific components perform on this emerging class of mobile devices. Although we have not done exhaustive testing, and although these browsers are revving quickly and present a moving target, our goal is to provide some early, provisional advice to help you get started as you contemplate how your YUI-based application will render in the mobile world.

More Information:

The Event Utility works in any browser that has DOM2 event support. However, the user interaction model of mobile browsers can make certain browser events behave in a different manner than expected, or not at all.

The iPhone's touch interface supports gestures that prevent certain mouse events from working correctly. For instance, the 'mousedown' event does not fire when the user initially touches the screen over an element. It only fires once the user's finger is removed (the mousedown, mouseup, and click events all fire at this moment). This makes is difficult or impossible to provide certain DHTML interactions that rely on these events, drag and drop being the most obvious.

Since the iPhone has a touch interface, there is no mouse cursor. This means that there are no hover states for elements, and no mouseover events.

Support & Community

Forums & Blog

YUI 3 discussion forums are hosted on YUILibrary.com.

In addition, please visit the YUIBlog for updates and articles about the YUI Library written by the library's developers.

Filing Bugs & Feature Requests

The YUI Library's public bug tracking and feature request repositories are located on the YUILibrary.com site. Before filing new feature requests or bug reports, please review our reporting guidelines.

Copyright © 2010 Yahoo! Inc. All rights reserved. Copyright | Privacy Policy | Terms of Use | Job Openings