Publish/subscribe
Like many libraries, Ractive implements the publish/subscribe mechanism to allow you to respond to, or trigger, particular events.
Subscribe
To subscribe to an event, use ractive.on():
ractive = new Ractive({
el: 'body',
template: '<button on-click="activate">click me!</button>'
});
ractive.on( 'activate', function () {
alert( 'Activating!' );
});
This can be used to subscribe to any of the following type of events:
- Proxy events for DOM and custom events defined in your template
- lifecycle events generated by each ractive instance - such as
init
,render
andteardown
- Custom events fired in code using ractive.fire(), which can be anything you like, see below.
Multiple events to one handler
You can subscribe a handler to more than one event by separating event names with a space:
ractive.on( 'activate select', function () {...} );
This example will fire for either an activate
event or a select
event.
Object map of multiple event/handler pairs
Multiple hander/function pairs can be subscribed using an object hash:
ractive.on({
activate: function () {...},
select: function () {...}
});
Wildcard pattern handlers
Event names that use a keypath-like name can be subscribed using the pattern-matching wildcard "*
" for any name path segment:
ractive.on( 'foo.*', function () {...} );
This example will fire on any event name that starts with foo.
- foo.active
, foo.select
, etc.
This is very useful with event bubbling and auto-prefixed event names that bubble up from components.
Be aware that handlers like widget.*
or *
will fire for all matching events, including lifecycle events.
Accessing the event object
In addition to the event argument that is passed with proxy events, the event object can be accessed using this.event
in the function body of any handler. This object is also present in non-proxy events including lifecycle events, though it includes a more limited set of properties.
Properties on all this.event
objects:
this.event.name
- the name of the eventthis.event.context
- the value ofthis.get(event.keypath)
orractive.get()
for non-proxy eventsthis.event.component
- the component that raised the event, only present on bubbled eventsthis.event.original
- the original DOM event, if available
Properties only on proxy events:
this.event.node
- the DOM node in questionthis.event.keypath
- the keypath of the current contextthis.event.index
- a map of index references
One useful aspect of this.event
is that the name of the event can be determined when wildcards are used:
ractive.on( 'foo.*', function () {
console.log( this.event.name );
});
Cancelling DOM events
If you return 'false' from a proxy event handler, ractive will automatically call both preventDefault()
and stopPropagation()
on the original DOM event.
Note that returning false
has a dual purpose of both cancelling the view hierarchy event bubbling as well as cancelling the DOM Event if the event was DOM-based.
Unsubscribe
Event handlers are automatically removed if the instance is torn down (e.g. with ractive.teardown()) (which also happens as components are removed due to template/data logic).
You can also unsubscribe event handlers manually using one of two approaches:
var listener = ractive.on( 'activate', function () {
alert( 'Activating!' );
});
// later...
listener.cancel();
or...
var handler = function () {
alert( 'Activating!' );
};
ractive.on( 'activate', handler );
// later...
ractive.off( 'activate', handler );
In the second case, note that if you don't specify a handler, all 'activate' handlers will be removed. If you don't specify an event name, all event handlers will be removed from the instance. See ractive.off() for more detail.
The ractive.off()
method is chainable for easily replacing subscribtions:
ractive.off( 'activate' ).on( 'activate', function () {...} );
Publish
In addition to the built-in lifecycle events and proxy events, you can fire your own events with ractive.fire().
This is most useful in the context of a component that needs to emit custom events. Here's a (somewhat contrived) example:
var Ticker = Ractive.extend({
oninit: function () {
var i = 1;
this.interval = setInterval( function () {
this.fire( 'tick', i++ );
}.bind( this ), 1000 );
},
onteardown: function () {
clearInterval( this.interval );
}
});
var ticker = new Ticker();
ticker.on( 'tick', function ( i ) {
console.log( i % 2 ? 'tick' : 'tock' );
});