Enyo Daily #6 - Events - Part 1
I should probably talk about the design goals addressed by events but that's not a topic I'm up for tonight. Instead, I'll jump into how events are handled in enyo and defer design talk for another day.[[MORE]]
There are two kinds of events in enyo: DOM and custom. DOM events are fired as a result of user interaction such as clicking a control, changing a value in a field, or resizing the window. Custom events are those defined on an enyo kind that are triggered at the discretion of the component.
Custom events are simpler so we'll start with those. These events are declared in the kind definition inside the "events" property. Enyo expects events to be prefixed by "on" and will both warn you and add the prefix itself if it discovers an event without it.
{
name:"ComponentName",
events:{
onEventName:""
}
}
During the component creation process, enyo will automatically add a function to the component which will "fire" the event. By default, the function will match the event name with "on" replaced with "do" (doEventName in the above example). This is actually customizable by specifying an object instead of an empty string as the value following the event name. For example, if you prefered fireEventName instead of doEventName, use this syntax:
{
name:"ComponentName",
events:{
onEventName:{caller:"fireEventName"}
}
}
You might be wondering why require an object literal to specify the caller if it's just a string; why not just pass "fireEventName" as the value and skip the object. The reason is that you can also specify a default handler name for the method. If the value following the event is a string, it is treated as the default handler name. If it's an object, it must be included as the value of the "value" property of that object.
{
name:"ComponentName",
events:{
onEventName:{caller:"fireEventName", value:"handleEventName"},
onAnotherEvent:"handleAnotherEvent"
}
}
If you're using a component that publishes an event, you can react to it by declaring the name of the handler method in the component declaration.
components:[
{kind:"ComponentName", onEventName:"myEventHandler"}
],
myEventHandler:function(source) {
// do something
}
If the kind specified a default handler (as illustrated above) and the owning object has a method of the same name, the declaration can be omitted.
components:[
{kind:"ComponentName", onEventName:"myEventHandler"}
],
myEventHandler:function(source) {
// do something
},
handleAnotherEvent:function(source) {
// will be found automatically since it matches the default handler name
}
Finally, here's a complete example. I've included some DOM event stuff that I'll cover in a future topic.
var _Example = {
name:"com.technisode.example.App",
kind:"Control",
components:[
{kind:"EventSender", name:"eventSender", onSend:"sent"},
{kind:"Button", onclick:"clicked"}
],
captureDomEvent:function(e) {
enyo.log("A DOM event occured", e.type);
// returning true would indicated the event is captured and prevent the bubble phase
// thereby preventing the declared handlers (clicked in this case) from being called
// returning false (or no explicit return) lets things continue
return false;
},
clicked:function() {
// trigger my custom events
this.$.eventSender.go();
// toggles event handler between send and secondSent ... just because ...
this.$.eventSender.onSend = (this.$.eventSender.onSend === "sent") ? "secondSent" : "sent";
},
sent:function(source, one, two, three) {
enyo.log("sent", one, two, three)
},
handleOnAlert:function(source, obj) {
enyo.log("alerted", enyo.json.stringify(obj));
},
secondSent:function(source, one, two, three) {
enyo.log("secondSent handles onSend now", one, two, three)
}
}
var _EventSender = {
name:"EventSender",
kind:"Component",
events:{
onSend:"handleOnSend",
onAlert:{value:"handleOnAlert", caller:"sendAlert"}
},
go:function() {
this.doSend(1,2,3); // dispatchIndirectly
this.sendAlert({a:1, b:2});
}
}
enyo.kind(_EventSender);
enyo.kind(_Example);