Reputation: 2394
I'd like to be able to use a public method for a callback instead of passing it as an argument
as in
function Car() {
var that = this;
this.onGearChanged = function(callback) {
callback();
};
setTimeout(that.onGearChanged, 2000);
}
var car = new Car();
car.onGearChanged(function(){
console.log("gear changed");
});
instead of
var onGearChanged = function(){
console.log("gear changed")
}
var car = new Car(arg, arg, onGearChange);
how would I go about it? Should i follow an observer pattern?
Upvotes: 0
Views: 174
Reputation: 512
The code will be more or less complex, depending on your requirements that are not clear. Don't use a pattern if you don't need it, and a pattern can be adjusted in many ways depending on your requirements. Don't try to build the all-for-all solution if you don't realy need it.
If you have many observers and know them at creation time of the car, you can use
function Car(onGearChangedArray) {
this.triggerGearChanged = function() {
for (var i=0;i<onGearChangedArray.length;i++) {
onGearChangedArray[i]();
}
};
window.setTimeout(this.triggerGearChanged,2000);
}
var car = new Car([function(){
console.log("gear changed");
}]);
If you only have exactly one observer, you can get rid of the for loop.
But if you need the flexibility to add them at runtime:
function Car() {
var onGearChangedCallbacks = [];
this.onGearChanged = function(callback) {
onGearChangedCallbacks.push(callback);
};
this.triggerGearChanged = function() {
for (var i=0;i<onGearChangedCallbacks.length;i++) {
onGearChangedCallbacks[i]();
}
};
window.setTimeout(this.triggerGearChanged,2000);
}
var car = new Car();
car.onGearChanged(function(){
console.log("gear changed");
});
Or if you want to abstract it the next level
function Event() {
var callbacks = [];
this.bind = function(callback) {
callbacks.push(callback);
};
this.fire = function() {
for (var i=0;i<callbacks.length;i++) {
callbacks[i]();
}
};
}
function Car() {
this.gearChanged = new Event();
window.setTimeout(this.gearChanged.fire,2000);
}
var car = new Car();
car.gearChanged.bind(function(){
console.log("gear changed");
});
Thanks for the abstraction idea to Khanh TO, I just wanted to show it without parameters.
You could also consider using something more sophisticated, so that you don't need to write this event handling code yourself (like error handling etc.), but again, it depends on your needs. Do you need a fail fast strategy, or should errors be just logged? Must Listeners be unregistered? Could you trap yourself in an infinite loop because triggerGearChanged could lead to another triggerGearChanged? Do you need to pass parameters or not? Keep in mind to keep it as simple as possible, so if you don't need to pass parameters, then don't do it.
If you like unserscore.js, a good start may be http://mattmueller.me/blog/underscore-extension-observer-pattern
Upvotes: 1
Reputation: 48982
I think you need something like this:
function Event(sender) {
this._sender = sender;
this._listeners = [];
}
Event.prototype = {
attach: function (listener) {
this._listeners.push(listener);
},
notify: function (args) {
for (var i = 0; i < this._listeners.length; i++) {
this._listeners[i](this._sender, args);
}
}
};
You Car
class:
function Car(gear) {
var self = this;
self.Gear = gear;
self.GearChanged = new Event(this);
//Example method to trigger your GearChanged event. In your real code, you may have different logic
self.changeGear = function (newGear){
self.Gear = newGear;
//notify all subscribers
self.GearChanged.notify(newGear);
}
}
Example code to subscribe to events:
var car = new Car("gear");
car.GearChanged.attach(function (sender,args){
console.log("gear changed");
console.log("new gear value is:" + args);
});
//do some logic that may trigger gearChanged event.
car.changeGear("new Gear");
You can attach more event handlers and all these event handlers will get called. And you can also add more events like: tireChanged,.. easily with this structure.
Upvotes: 1