I would like to use events to communicate between my objects in a google closure (GC) environment.
Suppose I have two classes foobar.Boss
and foobar.Employee
. The Boss wants to know when the Employee has made coffee, and whether or not that coffee is decaf (he's laying off the caffeine this week).
GC has made classes available that seem to provide the means to do this, goog.events.Event
and goog.events.EventTarget
.
Without knowing better, I'd think it would work like this:
foobar.Employee.prototype.makeCoffee = function(isDecaf)
{
this.coffeeMaker.putCoffeeInMachine(isDecaf);
this.coffeeMaker.start();
var event = new goog.event.Event('COFFEE_ON', { isDecaf: isDecaf });
goog.events.dispatchEvent(event);
}
foobar.Boss.prototype.addEmployee = function(employee)
{
...
goog.events.listen(employee, 'COFFEE_ON', function(e)
{
if (e.target.isDecaf)
{
this.refillMug();
}
}, false, this);
...
}
Is this a correct pattern? I am confused by the class goog.events.EventTarget
-- how does a target dispatch events? Doesn't a target have things happen to it?
This question is helpful, but a more direct answer would be appreciated.
Having looked at this for a while, my understanding is now that the EventTarget
in fact plays a dual roll of being the entity that dispatches events and the entity that is listened to. So one option would be to have Employee
inherit goog.events.EventTarget
but I have gone a different route.
First I created a new event type that would let the Boss know if the coffee was decaf.
/**
* @constructor
* @extends {goog.events.Event}
*/
foobar.CoffeeEvent = function(isDecaf)
{
goog.events.Event.call(this, 'COFFEE_ON');
this.isDecaf = isDecaf;
};
goog.inherits(foobar.CoffeeEvent, goog.events.Event);
Next I created an event listener type to dispatch these events.
/**
* @constructor
* @extends {goog.events.EventTarget}
*/
foobar.CoffeeEventTarget = function()
{
goog.events.EventTarget.call(this);
};
goog.inherits(foobar.CoffeeEventTarget, goog.events.EventTarget);
I added an object of this type to my Employee
.
foobar.Employee = function()
{
...
this.coffeeEvents = new foobar.CoffeeEventTarget();
...
}
When the employee refills the coffee:
foobar.Employee.prototype.makeCoffee = function(isDecaf)
{
this.coffeeMaker.putCoffeeInMachine(isDecaf);
this.coffeeMaker.start();
var event = new foobar.CoffeeEvent(isDecaf);
this.coffeeEvents.dispatchEvent(event);
}
Mr. Bossman listens for this.
foobar.Boss.prototype.addEmployee = function(employee)
{
...
goog.events.listen(employee.coffeeEvents, 'COFFEE_ON', function(e)
{
if (e.isDecaf)
{
this.refillMug();
}
}, false, this);
...
}
Note that this won't tell me which employee refilled the coffee, because the event target will an instance of CoffeeEventTarget
. If you wanted all of Employee
in there I suppose you could add it as a member field. If you were OK with inheriting to Employee
from goog.events.EventTarget
then you get Employee
for free as the target.