Enyo Daily #7 - Events - Part 2
In Part 1 about Events in enyo, I covered defining, triggering, and reacting to custom events for enyo Components. The other source is DOM events triggered by user interactions or window changes.[[MORE]]
First off, here are the supported DOM events in enyo:
Document Events
mousedown, mouseup, mouseover, mouseout, mousemove, click, dblclick, change, keydown, keyup, keypress, inputWindow Events
resize, load, unload
There are two phases to DOM event handling in enyo: capture and bubble. The capture phase starts with the eldest ancestor, calls captureDomEvent (if found), and continues downt the hierarchy until a captureDomEvent call returns true or reaches the source Control of the event.
If nothing captures the event, it's passed to the bubble phase. This phase traverses the opposite direction -- from node to parent. Again, if an event handler (dispatchDomEvent in the bubble phase) returns true, the phase stops; otherwise it continues until it reaches the top of the DOM tree. Also, if stopPropagation() is called on the event object, the phase will end as well.
Unlike the capture phase where you must implement captureDomEvent to handle the event, enyo.Component implements dispatchDomEvent and provides some basic routing. It first looks for a method matching the signature eventtypeHandler (e.g. clickHandler). If not found, it will look for an oneventtype (e.g. onclick) declaration and dispatch the event to it. Note that these handlers are mutually exclusive; if the first is found, the second will not be called.
Below is a slightly expanded example from the previous part that includes DOM event capturing and bubbling. If you try this code out, you can add different return values to see when events are stopped in each phase.
var _Example = {
name:"com.technisode.example.App",
kind:"Control",
components:[
{kind:"EventSender", name:"eventSender", onSend:"sent"},
{kind:"Button", onclick:"clicked"},
{kind:"Input", onkeypress:"press"}
],
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;
},
dispatchDomEvent:function(e) {
// like any other method, you could override dispatchDomEvent and implement custom routing
e.myCustomField = "This is a custom field";
return this.inherited(arguments);
},
press:function(source, event) {
enyo.log(source, event);
},
clickHandler:function(source, event) {
enyo.log("bubbled up to me", event.myCustomField);
// calling event.stopPropagation() or returning true will end the bubble phase
},
clicked:function(source, event) {
// 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";
// calling event.stopPropagation() or returning true will end the bubble phase
},
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);