Core.js provides several features for event driven development, including the Core.EventListenerList
for managing multiple types of event handlers, and Core.method()
as a convenient means of registering methods of object instances as event listeners.
Event-driven JavaScript objects typically provide the developer with the capability to register a Function
to be notified when an event occurs. The event-producing object will provide methods to add and remove Function
s to be notified of the event, and will invoke each of the registered functions when the event occurs, typically with the event as a parameter.
When an event handler Function
that is a method of an object instance is invoked, its this
-pointer will not be set to the object instance. It will be invoked as though it is a stand-alone function. For example, the following fragment of code which registers event listeners on an HTML element (hypothetically stored in this._buttonElement):
Core.extend({ clickCount: 0, registerListeners: function() { this.buttonElement.addEventListener("click", this._processClick, false); }, _processClick: function(e) { alert("This button has been clicked " + ++this.clickCount + " time(s)"); } });
Note: for the sake of simplicity, this example code is only compatible with browsers that support DOM events, i.e., not Internet Explorer.
In the above example, when processEvent()
is invoked, the this
-pointer will not reference the object instance. Thus the value of this.clickCount
will be undefined, and the code will not behave as desired.
Core's Core.method()
function can be used to solve this issue, by creating a closure which will invoke an event-listener method with the this
-pointer set to the appropriate object instance.
The following update to the listener registration code will allow the _processEvent()
method to be invoked on the correct object instance:
this.buttonElement.addEventListener("click", Core.method(this, this.processClick), false);
It is important to understand that the following code will evaluate to false:
Core.method(this, _processClick) == Core.method(this, _processClick)
The reason this will evaluate to false is because each invocation of Core.method()
will return a new Function
instance. For example, the following code will not remove the listener we registered earlier:
this.buttonElement.removeEventListener("click", this._processClick, false);
In the case where we need to unregister an event listener created with Core.method()
, it will be necessary to retain a reference to the Function
returned by Core.method()
. This Function
should then be passed to both the registration and unregistration methods, e.g.:
Core.extend({ clickCount: 0, _processClickRef: null, $construct: function() { this._processClickRef = Core.method(this, this._processClick); }, registerListeners: function() { this.buttonElement.addEventListener("click", this._processClickRef, false); }, unregisterListeners: function() { this.buttonElement.removeEventListener("click", this._processClickRef, false); }, _processClick: function(e) { alert("This button has been clicked " + ++this.clickCount + " time(s)"); } });
The Core.EventListenerList
object provides a convenient means for your event-producing objects to manage their registered listeners and dispatch events to them. Only a single Core.EventListenerList
is necessary per event-producing object, even if multiple types of listeners may be registered.
The following example shows a Core.EventListenerList
in use:
Core.extend({ _listeners: null, $construct: function() { this._listeners = new Core.EventListenerList(); }, addFooListener(l) { this._listeners.addListener("foo", l); }, foo() { this._listeners.fireEvent({source: this, type: "foo"}); }, removeFooListener(l) { this._listeners.removeListener("foo", l); } });
The addListener()
and removeListener()
events are used to register and unregister listeners, with the first parameter indicating the type of event and the second providing the listener to (un)register. When fireEvent()
is invoked, the provided event's type
property will be used to determine which listeners to notify. The provided event will be dispatched to all registered listeners of that type.