EventTarget

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.

The APIs for working with custom events are provided by the
EventTarget class. All other infrastructure classes extend
EventTarget, but if you just need the custom event APIs, you can
extend or augment your classes with EventTarget directly.

DEPRECATION NOTE: The subscribers and afters properties which
used to sit on CustomEvent object instances have been deprecated and
removed for performance reasons as of the 3.7.0 release.

If you're referring to the subscribers or afters properties directly just
to access the set of subscribers, consider switching to the public getSubs()
method instead which hides you from the implementation details.

If you have a use case which requires you to access the above properties
directly you can set Y.CustomEvent.keepDeprecatedSubs to true, to restore
them, but you will incur a performance hit if you enable this flag.

Getting Started

To include the source files for EventTarget and its dependencies, first load
the YUI seed file if you haven't already loaded it.

Next, create a new YUI instance for your application and populate it with the
modules you need by specifying them as arguments to the YUI().use() method.
YUI will automatically load any dependencies required by the modules you
specify.

<script>
// Create a new YUI instance and populate it with the required modules.
YUI().use('event-custom', function (Y) {
// EventTarget is available and ready for use. Add implementation
// code here.
});
</script>

Video Overview

This video from YUIConf 2009 gives a good overview of the YUI event system
API. The content covers DOM and custom events. Note: the synthetic event system was
updated since this video.

The Basics

You can get started using custom events and the EventTarget API without
creating your own class. The YUI instance (typically Y) is an
EventTarget, as is pretty much every other class in YUI. We'll go over
the basics using Y, then move into creating your own EventTargets.

If you've looked over the DOM
Event system docs, this should look very familiar. That's because
Nodes are also EventTargets.

All EventTargets host methods
on,
once,
after, and
onceAfter.
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
EventHandle. The
distinction between on and after is discussed in the
"after" phase section below.

Firing Events

// All subscribers to the myapp:ready event will be executed
Y.fire('myapp:ready');
// Pass along relevant data to the callbacks as arguments
Y.fire('birthday', {
name: 'Walt Disney',
birthdate: new Date(1901, 11, 5)
});

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.

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.

Custom event callbacks are usually, but not always passed an
EventFacade as their
first argument. Custom events can be configured to send event facades or
only the data they were fired with. Always
passing event data in an object 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
Publishing Events.

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.

EventTargets can be set up with a number of default configurations for
the events they fire. Pass the defaults as the fourth argument to
Y.augment.

Event facades mirror the event objects
you're familiar with from
the DOM. They have properties like e.type and e.target and
the same methods, allowing you to call e.preventDefault() to disable
default behavior you've configured for the event or e.stopPropagation()
to stop the event from bubbling.

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.

Bubbling Events

Events that are configured with emitFacade support bubbling to other
EventTargets, allowing you to subscribe to them from other objects, much
like DOM event bubbling. Add other EventTargets to an instance's bubble
path with addTarget.

Event Prefixes

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 code snippet above, configuring a default
prefix while augmenting the classes will allow for subscription to
only LeafNode updates.

Adding Default Behavior

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
doing
CRUD
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.

Unless configured with preventable: false, default behaviors can be
disabled with e.preventDefault() just like the DOM. Unlike their DOM
counterparts, though, event subscribers can change facade
properties to alter the default behavior by way of effectively changing
its input.

Broadcasting Events to Y or Between YUI instances

Event broadcasting is very similar to bubbling, but with some important
distinctions:

Broadcasting is specific to the YUI instance and the Y.Global shared
EventTarget

Events don't need to be configured with emitFacade to broadcast

Broadcasting happens after the default behavior, which also means...

Event behavior can't be prevented from broadcast subscribers

Broadcast can be defaulted for all events for an EventTarget

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

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.

For events configured to emitFacade allow bubbling events to
other EventTargets.

true

YES

defaultFn

Behavior associated with the event. Usually this is preventable
(see preventable below). Details above.

(none)

preventable

If set to false, e.preventDefault() will not disable execution
of the event's defaultFn.

true

preventedFn

Behavior associated with the event when e.preventDefault() is
called from a subscriber. Use this function to reset partially
applied transactional state.

Incompatible with preventable: false.

(none)

stoppedFn

Behavior associated with the event when e.stopPropagation() is
called from a subscriber. Seldom used.

(none)

async

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

false

The "after" phase

Unlike DOM events, custom events also expose an "after" phase that
corresponds to the time immediately after an event's default behavior executes. Subscribe to an event's
"after" phase with the after(...) method. The signature is the same as
on(...).

rootNode.after('tree:add', calc.updateTotals, calc);

The primary benefit of using after() subscriptions over on()
subscriptions is that if any on() subscribers call e.preventDefault(),
neither the event's configured defaultFnnor the after()
subscribers will be executed. If an after() subscription is
executed, you know that the defaultFn did as well.

Use after() to subscribe to events with a default behavior when
you want to react to the event with a side effect.

Use on() to subscribe to events if you need to prevent or alter
the default behavior or if they don't have default behavior.

Event Lifecycle

The order of operations when firing an event is as follows:

Simple Events (no facade)

on() subscribers are executed

after() subscribers are executed

Y.on() broadcast subscribers are executed.

Y.after() broadcast subscribers are executed.

Y.Global.on() broadcast subscribers are executed.

Y.Global.after() broadcast subscribers are executed.

If an on() or after() subscriber returns false, no more subscribers
will be notified.

Complex Events (with facade)

on() subscribers are executed

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.

If not prevented, any configured defaultFn will execute.

If bubbling was stopped, any configured stoppedFn will execute.

Y.on() broadcast subscribers are executed.

Y.after() broadcast subscribers are executed.

Y.Global.on() broadcast subscribers are executed.

Y.Global.after() broadcast subscribers are executed.

after() subscribers are executed.

after() subscribers for each bubble target and their respective
targets are executed.

The flow can be interrupted by on() subscribers doing any of these
things:

e.preventDefault()

The defaultFn will not be executed

The preventedFn will execute

No after() subscriptions will be executed

e.stopPropagation()

The remainder of subscribers at this EventTargetWILL execute

No bubble targets of this EventTarget will be notified

The stoppedFn will execute

The defaultFn and after() subscribers will execute

e.stopImmediatePropagation()

Same as e.stopPropagation() except no more subscribers at this
EventTarget will execute.