index.mustache revision c967f42c8ecf9b590ab1a9fca4f5d5d905fc1ded
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte<div class="intro">
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte The YUI Custom Event System enables you to define and use events beyond
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte those available in the DOM — events that are specific to and of
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte interest in your own application. Custom Events are designed to work
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte much like DOM events. They can bubble, pass event facades, have their
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte propagation and default behaviors suppressed, etc.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte The APIs for working with custom events are provided by the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte `EventTarget` class. All other infrastructure classes extend
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte `EventTarget`, but if you just need the custom event APIs, you can
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte `extend` or `augment` your classes with `EventTarget` directly.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte Bundled with `EventTarget` are <a
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte href="http://en.wikipedia.org/wiki/Aspect_oriented_programming">Aspect
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte Oriented Programming</a> methods that allow you to subscribe to the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte execution of object methods, and
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte<!-- insert Events Evolved video here -->
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte{{>getting-started}}
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte<h2>Video Overview</h2>
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte<iframe width="640" height="360" src="http://www.youtube.com/embed/s_7VjN3qxe8" frameborder="0" allowfullscreen></iframe>
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte This video from YUIConf 2009 gives a good overview of the YUI event system
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte API. The content covers DOM and custom events. Note: the <a
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte href="../event/index.html#synthetic-events">synthetic event</a> system was
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte updated since this video.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte<h2>The Basics</h2>
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte You can get started using custom events and the `EventTarget` API without
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte creating your own class. The YUI instance (typically `Y`) is an
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte `EventTarget`, as is pretty much every other class in YUI. We'll go over
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte the basics using `Y`, then move into creating your own `EventTarget`s.
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto If you've looked over the <a href="../event/index.html#the-basics">DOM
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto Event system docs</a>, this should look very familiar. That's because
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto `Node`s are also `EventTarget`s.
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto<h3>Subscribing to Events</h3>
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte// Custom events can have any name you want
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn ForteY.on('anyOldNameYouWant', function () {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte alert("Looky there!");
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// Group subscriptions by passing an object or array to on()
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto somethingImportant: updateCalendar,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte birthday : eatCake,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte weekendEnd : backToTheGrindstone
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte// Some events have prefixes
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn ForteY.once("fuji:available", climb);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte// Custom events have distinct "after" moments
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn ForteY.after("spa-category|pedicure", gelatoTime);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte All `EventTarget`s host methods
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte <a href="{{apiDocs}}/classes/EventTarget.html#method_on">`on`</a>,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte <a href="{{apiDocs}}/classes/EventTarget.html#method_once">`once`</a>,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte <a href="{{apiDocs}}/classes/EventTarget.html#method_after">`after`</a>, and
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte <a href="{{apiDocs}}/classes/EventTarget.html#method_onceAfter">`onceAfter`</a>.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte Both `once` and `onceAfter` will automatically detach the subscription
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte after the callback is executed the first time. All subscription methods
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return a subscription object called an
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte <a href="{{apiDocs}}/classes/EventHandle.html">EventHandle</a>. The
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte distinction between `on` and `after` is discussed in the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte <a href="#after">"after" phase</a> section below.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte<h3 id="fire">Firing Events</h3>
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte// All subscribers to the myapp:ready event will be executed
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoY.fire('myapp:ready');
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// Pass along relevant data to the callbacks as arguments
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoY.fire('birthday', {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto name: 'Walt Disney',
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte birthdate: new Date(1901, 11, 5)
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto<p id="event-data-object">
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto Notify event subscribers by calling `fire( eventName )`, passing any
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto extra data about the event as additional arguments. Though `fire`
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto accepts any number of arguments, it is preferable to send all event data
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte in an object passed as the second argument. Doing so avoids locking your
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto code into a specific `fire` and callback signature.
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// Subscription callbacks receive fire() arguments
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoY.on('birthday', function (name, birthdate) {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto var age = new Date().getFullYear() - birthdate.getFullYear();
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto alert('Happy ' + age + ', ' + name + '!');
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// Possible, but not recommended
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoY.fire('birthday', 'A. A. Milne', new Date(1882, 0, 18));
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// Instead, try to always pass only one object with all data
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoY.on('birthday', function (e) {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto var age = new Date().getFullYear() - e.birthdate.getFullYear();
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto alert('Happy ' + age + ', ' + e.name + '!');
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn ForteY.fire('birthday', {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte name: '"Uncle" Walt Whitman',
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto birthdate: new Date(1819, 4, 31)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte In the world of DOM events, the `fire` step is something the browser is
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte responsible for. A typical model involves the browser receiving keyboard
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte input from the user and firing `keydown`, `keyup`, and `keypress` events.
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto Custom events put your code in the position of dispatching events in
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto response to criteria that are relavant to your objects or application.
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto<h3>Callback arguments and event facades</h3>
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// Simple notification events don't send event objects, only fire() data
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoY.on('talkie', function (data) {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto alert('(' + data.time + ') Walkie ' + data.message);
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto // data.preventDefault is not defined. data is just a plain object
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto message: 'roger, over.',
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto time: new Date()
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// Events configured to emitFacade will send an event object, merged with
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// fire() data
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto emitFacade: true,
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto defaultFn : payUp
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoY.on('bill:due', function (e) {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto // Event facades have standard properties and methods as well as properties
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto // from payload data passed to fire()
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto if (e.payee === 'Rich Uncle Sal') {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto e.preventDefault(); // the `payUp` method won't be called (Sal can wait)
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// Objects passed as the second argument to fire() for facade events will have
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// their properties merged onto the facade received by the callback.
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoY.fire('bill:due', {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto payee: 'Great Aunt Myra',
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto Custom event callbacks are <em>usually, but not always</em> passed an
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto <a href="{{apiDocs}}/classes/EventFacade.html">EventFacade</a> as their
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto first argument. Custom events can be configured to send event facades or
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto only the data they were fired with. <a href="#event-data-object">Always
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto passing event data in an object</a> as the second argument to `fire` allows
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto you to write all your callbacks to expect event data as a single first
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto argument, whether it's an `EventFacade` or just a plain object. The
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto `emitFacade` and `defaultFn` configurations are detailed below, in
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto <a href="#publishing-events">Publishing Events</a>.
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto<h3>Detaching Event Subscriptions</h3>
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte// Subscription methods return a subscription handle...
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetovar subscription = Y.on('myapp:ready', initComponents);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte// ...with a detach method
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// Or detach by signature
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoY.detach('myapp:ready', initComponents);
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// Or by subscription category
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoY.on('spa-category|pedicure', gelatoTime);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte// Detach subscriptions to all events in the spa-category subscription group
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn ForteY.detach('spa-category|*');
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte The preferred method of detaching subscriptions is to use the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte <a href="{{apiDocs}}/classes/EventHandle.html">EventHandle</a> that is
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto returned from the subscription methods. Alternately you can use the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte <a href="{{apiDocs}}/classes/EventTarget.html#method_detach">`detach` or
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto `detachAll` methods</a> which work as described in the
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto <a href="../event/index.html#detach-methods">Event user guide</a>.
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto<h3 id="extend-event-target">Extending EventTarget</h3>
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto<p>Add the `EventTarget` APIs onto any class using `Y.augment()`.</p>
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetofunction MyClass() {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto /* insert constructor logic here */
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto add: function (item) {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto // You can assume the APIs are available from your class instances
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto this.fire("addItem", { item: item });
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// Make MyClass an EventTarget
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetovar instance = new MyClass();
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoinstance.on('addItem', function (e) {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto alert("Yay, I'm adding " + e.item);
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoinstance.add('a new item'); // ==> "Yay, I'm adding a new item"
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto `Y.augment` works like a lazy `extend` or a mixin. It adds the APIs to the
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto host class, but on the first call to any of the methods, it calls the
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto `EventTarget` constructor on the instance to make sure the necessary
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto internal objects are ready for use. If your class extends another,
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto augmenting it won't interfere with that inheritance hierarchy.
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto `EventTarget`s can be set up with a number of default configurations for
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto the events they `fire`. Pass the defaults as the fourth argument to
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// Make all events fired from MyClass instances send an event facade
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto emitFacade: true
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto<h2>Publishing Events</h2>
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto Some custom event <a href="#configs">configurations can be defaulted</a>
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto from class configuration, but others need to be specified on a per-event
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto basis. Use the `publish` method to do this.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte// publish takes an event name and a configuration object
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn ForteY.publish('somethingSpecial', {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte emitFacade: true,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte broadcast: 2,
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto defaultFn: clapClapHallelujah,
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto fireOnce: true
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto<h3 id="facade">Event Facades</h3>
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto The most common configuration for custom events is `emitFacade`. This is
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto because with the event facades comes a lot of additional functionality,
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto such as <a href="#defaultFn">preventable default behaviors</a> and <a
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto href="#bubbling">bubbling</a>.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefunction Recipe() {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte // publishing events is typically done at instantiation
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto emitFacade: true,
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto defaultFn: this._defAddFn
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto Event facades mirror the event objects
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto <a href="../event/index.html#facade-properties">you're familiar with from
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte the DOM</a>. They have properties like `e.type` and `e.target` and
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte the same methods, allowing you to call `e.preventDefault()` to disable
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte default behavior you've configured for the event or `e.stopPropagation()`
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte to stop the event from bubbling.
7b506e25917c371db526f76d85b9b1d17c8c5d39srivijitha dugganapallivar gruel = new Recipe();
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortegruel.on('add', function (e) {
7b506e25917c371db526f76d85b9b1d17c8c5d39srivijitha dugganapalli if (e.item === "brussel sprouts") {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte // call e.preventDefault() just as you would for DOM events
7b506e25917c371db526f76d85b9b1d17c8c5d39srivijitha dugganapalli e.preventDefault(); // brussel sprouts? eww!
7b506e25917c371db526f76d85b9b1d17c8c5d39srivijitha dugganapalli `emitFacade` is typically passed as a default configuration to `Y.augment`.
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto All other YUI infrastructure classes extend `EventTarget` and set
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto `emitFacade` to `true` for you.
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto add: function (item) {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto // This will fire with an event facade because Y.Base sets emitFacade to true
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto this.fire('addItem', { item: item });
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto<h3 id="once">`fireOnce` Events</h3>
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto Important, typically system-level or lifecycle related events can be
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto configured as `fireOnce`. These events mimic things like `window.onload`
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto or the `domready` event.
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoWidget.prototype.render = function (where) {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto // Widget rendering only happens once
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto defaultFn: this._defRenderFn,
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto fireOnce: true,
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto this.fire('render', ...);
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto After `fireOnce` events have been `fire()`d, any subsequent (late)
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto subscriptions are immediately executed. This can introduce race
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte conditions, however, since subscribers might expect to be called at a later
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto time, after the code that follows the subscription has also executed. In
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto this case, you can configure `fireOnce` events with the `async` flag
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto and post-`fire` subscriptions will be executed in a `setTimeout`,
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto allowing all subsequent code to run before the late subscriber is notified.
7b506e25917c371db526f76d85b9b1d17c8c5d39srivijitha dugganapalli// ... elsewhere in the code
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// If myapp:ready has been fired, setStuffUp executes right now, but might
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// expect MyApp.Stuff to be created already. So, boom.
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoY.on('myapp:ready', setStuffUp);
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoY.publish('myapp:ready', {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto fireOnce: true,
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto async : true
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte// ... elsewhere in the code
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte// Even if myapp:ready has been fired, setStuffUp will execute later. So, no boom
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoY.on('myapp:ready', setStuffUp);
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto<h3 id="bubbling">Bubbling Events</h3>
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte Events that are configured with `emitFacade` support bubbling to other
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte `EventTarget`s, allowing you to subscribe to them from other objects, much
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte like DOM event bubbling. Add other `EventTarget`s to an instance's bubble
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte path with `addTarget`.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefunction LeafNode() { ... }
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoLeafNode.prototype.rename = function (newName) {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto var oldName = this.name;
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto prevVal: oldName,
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto newVal : newName
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortefunction TreeNode() { ... }
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoTreeNode.prototype.add = function (node) {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto // The new child node's events will bubble to this TreeNode
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn ForteY.augment(LeafNode, Y.EventTarget, true, null, { emitFacade: true });
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoY.augment(TreeNode, Y.EventTarget, true, null, { emitFacade: true });
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetovar rootNode = new TreeNode("ROOT"),
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto branchA = new TreeNode("branchA"),
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto leaf1 = new LeafNode("leaf1");
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetorootNode.add(branchA); // ROOT
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetorootNode.add( new LeafNode("leaf2") ); // / \
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto // branchA leaf2
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetobranchA.add(leaf1); // / \
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetobranchA.add( new LeafNode("leaf3") ); // leaf1 leaf3
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// Subscribe to 'update' events from any leaf or tree node under root
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn ForterootNode.on('update', function (e) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte alert(e.prevVal + " has been renamed " + e.newVal);
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoleaf1.rename("Flower!"); // ==> "leaf1 has been renamed Flower!"
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto<h3 id="prefix">Event Prefixes</h3>
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto Individual events or all events fired by an `EventTarget` can be configured
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto to include a prefix to help filter subscriptions to common event names by
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto their origin. Prefixed event names look like `'prefix:eventName'`.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte Taking the <a href="#bubbling">code snippet above</a>, configuring a default
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte `prefix` while augmenting the classes will allow for subscription to
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto only `LeafNode` updates.
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// All events fired by LeafNode instances will be prefixed with "leaf:"
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto emitFacade: true,
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto prefix: 'leaf'
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// ...and for TreeNodes, "tree:"
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto emitFacade: true,
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto prefix: 'tree'
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// Listen specifically for changes from LeafNodes
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetorootNode.on('leaf:update', function (e) {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto alert(e.prevVal + " has been renamed " + e.newVal);
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoleaf1.rename("Flower!"); // ==> "leaf1 has been renamed Flower!"
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetobranchA.rename("Chewbacca!"); // (nothing)
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto Subscribing with prefixes is similar to
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto <a href="../event/delegation.html">using DOM event delegation</a>, though it
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto is done using `on()` rather than `delegate()`.
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto Optionally, you can omit the prefix when subscribing on the object that
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto fires the event.
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// prefix is optional when subscribing on the firing object...
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoleaf1.on('leaf:update', worksJustLike);
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoleaf1.on('update', function (e) {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto e.type; // 'leaf:update' -- the event type will remain prefixed
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// ...but prefixes are required from other objects
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetorootNode.on('update', function (e) {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto // will not capture leaf:update events
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto Subscribe to all events of a specific type, regardless of prefix, using the
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto wildcard prefix `*:eventName`.
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// Execute the callback if either the group object or one of its items fires an
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// `update` event
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetorootNode.on('*:update', function (e) {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto case "leaf:update": ...
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto case "tree:update": ...
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto<h3 id="defaultFn">Adding Default Behavior</h3>
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto Custom events can be bound to behaviors just like DOM events (e.g. clicking
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto on a link causes navigation to a new page). This is especially useful when
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte <a href="http://en.wikipedia.org/wiki/Create,_read,_update_and_delete">CRUD</a>
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte operations that you want to expose to other objects in your system to
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte prevent, alter, or enhance.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte Add a default behavior to an event by configuring the event's `defaultFn`.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte By convention, default functions are named `_def(the name of the event)Fn`.
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetofunction TreeNode(name) {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto this._items = [];
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto // Event publishing is typically done during instantiation
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto defaultFn: this._defAddFn
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// Adding a child node is an interesting mutation operation. Move the mutation
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// logic from the method to a mutation event's default behavior
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoTreeNode.prototype.add = function (node) {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto this.fire('add', { newNode: node });
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// Default functions receive the event facade like other subscribers
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetobranchA.add(leaf1); // without 'add' subscriptions, the behavior is the same
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte Unless configured with `preventable: false`, default behaviors can be
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte disabled with `e.preventDefault()` just like the DOM. Unlike their DOM
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto counterparts, though, event subscribers <em>can change facade
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto properties</em> to alter the default behavior by way of effectively changing
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn ForteTreeNode.prototype.add = function (node) {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto newNode: node,
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto bubbleEvents: true
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte// Default functions receive the event facade like other subscribers
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// You can prevent default behavior from anywhere along the bubble path
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetorootNode.on('tree:add', function (e) {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto if (e.newNode.name === "Leafy") {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto } else if (e.newNode.name === "James Bond") {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto e.bubbleEvents = false; // Shhhh
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn ForterootNode.add( new LeafNode("Leafy") ); // Node NOT added
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn ForterootNode.add( new LeafNode("James Bond") ); // Node added without event bubbling
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte<h3>Broadcasting Events to Y or Between YUI instances</h3>
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte Event broadcasting is very similar to bubbling, but with some important
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte distinctions:
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte Broadcasting is specific to the YUI instance and the `Y.Global` shared
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte `EventTarget`
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte <li>Events don't need to be configured with `emitFacade` to broadcast</li>
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte <li>Broadcasting happens after the default behavior, which also means...</li>
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte <li>Event behavior can't be prevented from broadcast subscribers</li>
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte <li>Broadcast can be defaulted for all events for an `EventTarget`</li>
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto Broadcasting is essentially a "fast track" bubbling configuration allowing
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte you to specify that events can be subscribed to from the YUI instance (with
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto `broadcast: 1`) or from `Y.Global` (with `broadcast: 2`).
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// All events from instances of MyClass can be subscribed from Y.on()
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto emitFacade: true,
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto prefix: 'awesome',
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto broadcast: 1
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto// Respond to a 'thing' event from any instance of MyClass in the YUI sandbox
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoY.on('awesome:song', partyOn);
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetovar instance = new MyClass()
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoinstance.fire("song", { which: "Bohemian Rhapsody", whom: "Wayne" });
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto `Y.Global` is an `EventTarget` that is shared between all YUI instances,
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto allowing cross-sandbox communication. To avoid feedback loops, it's best
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto to add an instance identity to outgoing events and only respond to
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto incoming events from other identities.
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoYUI().use('node', 'event-custom', function (Y) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte var id = "Alpha Beta Base"; // probably Y.guid() would be safer
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto // Stamp outgoing messages with this instance's id
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto Y.on('*:message', function (e) {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto Y.Global.on('*:message', function (e) {
450396635f70344c58b6b1e4db38cf17ff34445cJohn Forte if (e.origin !== id) {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto alert("message received from " + e.origin + ": " + e.message);
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto function Character() {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto this.publish('message', { broadcast: 2 });
450396635f70344c58b6b1e4db38cf17ff34445cJohn Forte emitFacade: true,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte var murdock = new Character();
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto Y.one('#status').on('click', function () {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte message: "You're coming in too fast!"
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szetoYUI().use('event-custom', function (OtherY) {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto var id = "Lunar Shuttle";
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto // ...(the same setup as above)...
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto var striker = new Character()
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto Y.one('#status').on('click', function () {
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto message: "She's beginning to crack up"
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto<!--h3>Monitoring Events</h3>
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto<p>TODO</p-->
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto<h3 id="configs">Available Event Configurations and Defaults</h3>
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto Events can be configured with the following properties. Properties marked
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto as "Class Configurable" can be passed to the `EventTarget` constructor
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte configuration to default for all events.
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto <th>Configuration</th>
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto <th>Description</th>
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto <th>Default</th>
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto <th>Class Configurable?</th>
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto <td>`prefix`</td>
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto `e.type` will always include the configured prefix.
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto <a href="#prefix">Details above</a>.
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto <td>(empty)</td>
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto <td>YES</td>
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto <td>`context`</td>
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto The default `this` object to execute callbacks with. Rarely set.
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto <td>The instance</td>
8fe960854f0d52e2e8a80ba68e8621a5ac6a866dtim szeto <td>YES</td>
<em>and</em> `Y.Global` with the event.
If set to `false`, `e.preventDefault()` will not disable execution
Behavior associated with the event when `e.preventDefault()` is
Behavior associated with the event when `e.stopPropagation()` is
subscriptions is that if any `on()` subscribers call `e.preventDefault()`,
<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>`Y.Global.after()` broadcast 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>
<li>`Y.Global.after()` broadcast subscribers are executed.</li>
<dt>`e.preventDefault()`</dt>
<dt>`e.stopPropagation()`</dt>
<dt>`e.stopImmediatePropagation()`</dt>
Same as `e.stopPropagation()` except no more subscribers at this
<dt>`e.halt()`</dt>
<dt>`e.halt(true)`</dt>
<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>