2N/A The YUI Custom Event System enables you to define and use events beyond
2N/A those available in the DOM — events that are specific to and of
2N/A interest in your own application. Custom Events are designed to work
2N/A much like DOM events. They can bubble, pass event facades, have their
2N/A propagation and default behaviors suppressed, etc.
2N/A The APIs for working with custom events are provided by the
2N/A `EventTarget` class. All other infrastructure classes extend
2N/A `EventTarget`, but if you just need the custom event APIs, you can
2N/A `extend` or `augment` your classes with `EventTarget` directly.
2N/A Bundled with `EventTarget` are <a
2N/A Oriented Programming</a> methods that allow you to subscribe to the
2N/A execution of object methods, and
2N/A<!-- insert Events Evolved video here -->
2N/A<h2>Video Overview</h2>
2N/A This video from YUIConf 2009 gives a good overview of the YUI event system
2N/A API. The content covers DOM and custom events. Note: the <a
2N/A updated since this video.
2N/A You can get started using custom events and the `EventTarget` API without
2N/A creating your own class. The YUI instance (typically `Y`) is an
2N/A `EventTarget`, as is pretty much every other class in YUI. We'll go over
2N/A the basics using `Y`, then move into creating your own `EventTarget`s.
2N/A Event system docs</a>, this should look very familiar. That's because
2N/A `Node`s are also `EventTarget`s.
2N/A<h3>Subscribing to Events</h3>
2N/A// Custom events can have any name you want
2N/AY.on('anyOldNameYouWant', function () {
2N/A alert("Looky there!");
2N/A// Group subscriptions by passing an object or array to on()
2N/A somethingImportant: updateCalendar,
2N/A weekendEnd : backToTheGrindstone
2N/A// Some events have prefixes
Y.once("fuji:available", climb);
// Custom events have distinct "after" moments
Y.after("spa-category|pedicure", gelatoTime);
All `EventTarget`s host methods
Both `once` and `onceAfter` will automatically detach the subscription
after the callback is executed the first time. All subscription methods
return a subscription object called an
distinction between `on` and `after` is discussed in the
<a href="#after">"after" phase</a> section below.
<h3 id="fire">Firing Events</h3>
// All subscribers to the myapp:ready event will be executed
// Pass along relevant data to the callbacks as arguments
birthdate: new Date(1901, 11, 5)
<p id="event-data-object">
Notify event subscribers by calling `fire( eventName )`, passing any
extra data about the event as additional arguments. Though `fire`
accepts any number of arguments, it is preferable to send all event data
in an object passed as the second argument. Doing so avoids locking your
code into a specific `fire` and callback signature.
// Subscription callbacks receive fire() arguments
Y.on('birthday', function (name, birthdate) {
alert('Happy ' + age + ', ' + name + '!');
// Possible, but not recommended
Y.fire('birthday', 'A. A. Milne', new Date(1882, 0, 18));
// Instead, try to always pass only one object with all data
Y.on('birthday', function (e) {
alert('Happy ' + age + ', ' +
e.name + '!');
name: '"Uncle" Walt Whitman',
birthdate: new Date(1819, 4, 31)
In the world of DOM events, the `fire` step is something the browser is
responsible for. A typical model involves the browser receiving keyboard
input from the user and firing `keydown`, `keyup`, and `keypress` events.
Custom events put your code in the position of dispatching events in
response to criteria that are relavant to your objects or application.
<h3>Callback arguments and event facades</h3>
// Simple notification events don't send event objects, only fire() data
Y.on('talkie', function (data) {
// Events configured to emitFacade will send an event object, merged with
Y.on('bill:due', function (e) {
// Event facades have standard properties and methods as well as properties
// from payload data passed to fire()
if (
e.payee === 'Rich Uncle Sal') {
// Objects passed as the second argument to fire() for facade events will have
// their properties merged onto the facade received by the callback.
payee: 'Great Aunt Myra',
Custom event callbacks are <em>usually, but not always</em> passed an
first argument. Custom events can be configured to send event facades or
only the data they were fired with. <a href="#event-data-object">Always
passing event data in an object</a> as the second argument to `fire` allows
you to write all your callbacks to expect event data as a single first
argument, whether it's an `EventFacade` or just a plain object. The
`emitFacade` and `defaultFn` configurations are detailed below, in
<a href="#publishing-events">Publishing Events</a>.
<h3>Detaching Event Subscriptions</h3>
// Subscription methods return a subscription handle...
var subscription =
Y.on('myapp:ready', initComponents);
// Or detach by signature
Y.detach('myapp:ready', initComponents);
// Or by subscription category
Y.on('spa-category|pedicure', gelatoTime);
// Detach subscriptions to all events in the spa-category subscription group
The preferred method of detaching subscriptions is to use the
returned from the subscription methods. Alternately you can use the
`detachAll` methods</a> which work as described in the
<h3 id="extend-event-target">Extending EventTarget</h3>
<p>Add the `EventTarget` APIs onto any class using `
Y.augment()`.</p>
/* insert constructor logic here */
// You can assume the APIs are available from your class instances
// Make MyClass an EventTarget
var instance = new MyClass();
alert("Yay, I'm adding " +
e.item);
instance.add('a new item'); // ==> "Yay, I'm adding a new item"
`
Y.augment` works like a lazy `extend` or a mixin. It adds the APIs to the
host class, but on the first call to any of the methods, it calls the
`EventTarget` constructor on the instance to make sure the necessary
internal objects are ready for use. If your class extends another,
augmenting it won't interfere with that inheritance hierarchy.
`EventTarget`s can be set up with a number of default configurations for
the events they `fire`. Pass the defaults as the fourth argument to
// Make all events fired from MyClass instances send an event facade
<h2>Publishing Events</h2>
Some custom event <a href="#configs">configurations can be defaulted</a>
from class configuration, but others need to be specified on a per-event
basis. Use the `publish` method to do this.
// publish takes an event name and a configuration object
defaultFn: clapClapHallelujah,
<h3 id="facade">Event Facades</h3>
The most common configuration for custom events is `emitFacade`. This is
because with the event facades comes a lot of additional functionality,
such as <a href="#defaultFn">preventable default behaviors</a> and <a
href="#bubbling">bubbling</a>.
// publishing events is typically done at instantiation
defaultFn: this._defAddFn
Event facades mirror the event objects
to stop the event from bubbling.
var gruel = new Recipe();
if (
e.item === "brussel sprouts") {
`emitFacade` is typically passed as a default configuration to `
Y.augment`.
All other YUI infrastructure classes extend `EventTarget` and set
`emitFacade` to `true` for you.
// This will fire with an event facade because
Y.Base sets emitFacade to true
<h3 id="once">`fireOnce` Events</h3>
Important, typically system-level or lifecycle related events can be
configured as `fireOnce`. These events mimic things like `
window.onload`
// Widget rendering only happens once
defaultFn: this._defRenderFn,
After `fireOnce` events have been `fire()`d, any subsequent (late)
subscriptions are immediately executed. This can introduce race
conditions, however, since subscribers might expect to be called at a later
time, after the code that follows the subscription has also executed. In
this case, you can configure `fireOnce` events with the `async` flag
and post-`fire` subscriptions will be executed in a `setTimeout`,
allowing all subsequent code to run before the late subscriber is notified.
// ... elsewhere in the code
// If myapp:ready has been fired, setStuffUp executes right now, but might
Y.on('myapp:ready', setStuffUp);
// ... elsewhere in the code
// Even if myapp:ready has been fired, setStuffUp will execute later. So, no boom
Y.on('myapp:ready', setStuffUp);
<h3 id="bubbling">Bubbling Events</h3>
Events that are configured with `emitFacade` support bubbling to other
`EventTarget`s, allowing you to subscribe to them from other objects, much
like DOM event bubbling. Add other `EventTarget`s to an instance's bubble
function LeafNode() { ... }
function TreeNode() { ... }
// The new child node's events will bubble to this TreeNode
var rootNode = new TreeNode("ROOT"),
branchA = new TreeNode("branchA"),
leaf1 = new LeafNode("leaf1");
// Subscribe to 'update' events from any leaf or tree node under root
leaf1.rename("Flower!"); // ==> "leaf1 has been renamed Flower!"
<h3 id="prefix">Event Prefixes</h3>
Individual events or all events fired by an `EventTarget` can be configured
to include a prefix to help filter subscriptions to common event names by
their origin. Prefixed event names look like `'prefix:eventName'`.
Taking the <a href="#bubbling">code snippet above</a>, configuring a default
`prefix` while augmenting the classes will allow for subscription to
// All events fired by LeafNode instances will be prefixed with "leaf:"
//
...and for TreeNodes, "tree:"
// Listen specifically for changes from LeafNodes
leaf1.rename("Flower!"); // ==> "leaf1 has been renamed Flower!"
Subscribing with prefixes is similar to
is done using `on()` rather than `delegate()`.
Optionally, you can omit the prefix when subscribing on the object that
// prefix is optional when subscribing on the firing object...
e.type; // 'leaf:update' -- the event type will remain prefixed
//
...but prefixes are required from other objects
// will not capture leaf:update events
Subscribe to all events of a specific type, regardless of prefix, using the
wildcard prefix `*:eventName`.
// Execute the callback if either the group object or one of its items fires an
<h3 id="defaultFn">Adding Default Behavior</h3>
Custom events can be bound to behaviors just like DOM events (
e.g. clicking
on a link causes navigation to a new page). This is especially useful when
operations that you want to expose to other objects in your system to
prevent, alter, or enhance.
Add a default behavior to an event by configuring the event's `defaultFn`.
By convention, default functions are named `_def(the name of the event)Fn`.
function TreeNode(name) {
// Event publishing is typically done during instantiation
defaultFn: this._defAddFn
// Adding a child node is an interesting mutation operation. Move the mutation
// logic from the method to a mutation event's default behavior
// Default functions receive the event facade like other subscribers
branchA.add(leaf1); // without 'add' subscriptions, the behavior is the same
Unless configured with `preventable: false`, default behaviors can be
counterparts, though, event subscribers <em>can change facade
properties</em> to alter the default behavior by way of effectively changing
// Default functions receive the event facade like other subscribers
// You can prevent default behavior from anywhere along the bubble path
rootNode.add( new LeafNode("James Bond") ); // Node added without event bubbling
<h3>Broadcasting Events to Y or Between YUI instances</h3>
Event broadcasting is very similar to bubbling, but with some important
Broadcasting is specific to the YUI instance and the `
Y.Global` shared
<li>Events don't need to be configured with `emitFacade` to broadcast</li>
<li>Broadcasting happens after the default behavior, which also means...</li>
<li>Event behavior can't be prevented from broadcast subscribers</li>
<li>Broadcast can be defaulted for all events for an `EventTarget`</li>
Broadcasting is essentially a "fast track" bubbling configuration allowing
you to specify that events can be subscribed to from the YUI instance (with
`broadcast: 1`) or from `
Y.Global` (with `broadcast: 2`).
// All events from instances of MyClass can be subscribed from
Y.on()
// Respond to a 'thing' event from any instance of MyClass in the YUI sandbox
Y.on('awesome:song', partyOn);
var instance = new MyClass()
instance.fire("song", { which: "Bohemian Rhapsody", whom: "Wayne" });
`
Y.Global` is an `EventTarget` that is shared between all YUI instances,
allowing cross-sandbox communication. To avoid feedback loops, it's best
to add an instance identity to outgoing events and only respond to
incoming events from other identities.
YUI().use('node', 'event-custom', function (Y) {
var id = "Alpha Beta Base"; // probably
Y.guid() would be safer
// Stamp outgoing messages with this instance's id
Y.on('*:message', function (e) {
var murdock = new Character();
Y.one('#status').on('click', function () {
message: "You're coming in too fast!"
YUI().use('event-custom', function (OtherY) {
var id = "Lunar Shuttle";
// ...(the same setup as above)...
var striker = new Character()
Y.one('#status').on('click', function () {
message: "She's beginning to crack up"
<!--h3>Monitoring Events</h3>
<h3 id="configs">Available Event Configurations and Defaults</h3>
Events can be configured with the following properties. Properties marked
as "Class Configurable" can be passed to the `EventTarget` constructor
configuration to default for all events.
<th>Class Configurable?</th>
`
e.type` will always include the configured prefix.
<a href="#prefix">Details above</a>.
The default `this` object to execute callbacks with. Rarely set.
If `true`, sends event facades to callbacks, allows bubbling and
default functions, etc. This is commonly set to true for a class.
<a href="#facade">Details above</a>.
If `true`, events will only fire once. Subscriptions made after
firing will be immediately executed.
<a href="#once">Details above</a>.
Allows you to subscribe to the event lifecycle moments (publish,
fire, and subscribe) as separate events.
<a href="#monitor">Details above</a>.
Notify the YUI instance (`broadcast: 1`) or the YUI instance
<a href="#broadcast">Details above</a>.
<td>0 (instance only)</td>
For events configured to `emitFacade` allow bubbling events to
Behavior associated with the event. Usually this is preventable
(see `preventable` below). <a href="#defaultFn">Details above</a>.
of the event's `defaultFn`.
called from a subscriber. Use this function to reset partially
applied transactional state.
<p>Incompatible with `preventable: false`.</p>
called from a subscriber. Seldom used.
Only applicable to events also configured with `fireOnce: true`.
If `true`, new subscriptions to this event after it has already
been fired will be queued to execute in a `setTimeout` instead of
immediately (synchronously).
<h3 id="after">The "after" phase</h3>
Unlike DOM events, custom events also expose an "after" phase that
corresponds to the time immediately after an event's <a
href="#defaultFn">default behavior</a> executes. Subscribe to an event's
"after" phase with the `after(...)` method. The signature is the same as
The primary benefit of using `after()` subscriptions over `on()`
neither the event's configured `defaultFn` <em>nor the `after()`
subscribers</em> will be executed. If an `after()` subscription is
executed, you know that the `defaultFn` did as well.
<strong>Use `after()` to subscribe to events with a default behavior when
you want to react to the event with a side effect.</strong>
<strong>Use `on()` to subscribe to events if you need to prevent or alter
the default behavior or if they don't have default behavior.</strong>
<p>The order of operations when firing an event is as follows:</p>
<h3 id="simple-event-lifecycle">Simple Events (no facade)</h3>
<li>`on()` subscribers are executed</li>
<li>`after()` subscribers are executed</li>
<li>`
Y.on()` broadcast subscribers are executed.</li>
<li>`
Y.after()` broadcast subscribers are executed.</li>
<li>`
Y.Global.on()` broadcast subscribers are executed.</li>
If an `on()` or `after()` subscriber returns `false`, no more subscribers
<h3 id="complex-event-lifecycle">Complex Events (with facade)</h3>
<li>`on()` subscribers are executed</li>
`on()` subscribers for each bubble target and their respective targets
are executed until all targets' bubble paths are walked or a subscriber
stops the propagation of the event.
If the event was prevented, any configured `preventedFn` will execute.
<li>If not prevented, any configured `defaultFn` will execute.</li>
<li>If bubbling was stopped, any configured `stoppedFn` will execute.</li>
<li>`
Y.on()` broadcast subscribers are executed.</li>
<li>`
Y.after()` broadcast subscribers are executed.</li>
<li>`
Y.Global.on()` broadcast subscribers are executed.</li>
<li>`after()` subscribers are executed.</li>
`after()` subscribers for each bubble target and their respective
The flow can be interrupted by `on()` subscribers doing any of these
<li>The `defaultFn` will not be executed</li>
<li>The `preventedFn` will execute</li>
<li>No `after()` subscriptions will be executed</li>
<li>The remainder of subscribers at this `EventTarget` <strong>WILL</strong> execute</li>
<li>No bubble targets of this `EventTarget` will be notified</li>
<li>The `stoppedFn` will execute</li>
<li>The `defaultFn` and `after()` subscribers will execute</li>
`EventTarget` will execute.
<dd>Same as `
e.halt(true)`. Not recommended. Use the API methods.</dd>
<!--h2 class="no-toc">Subscribing to Object Methods with `
Y.Do.*`</h2>
<h3 class="no-toc">Before and After</h3>
<h3 class="no-toc">Altering the Wrapped Method Behavior</h3>
<h3 class="no-toc">`EventTarget` API methods</h3>