0

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?

1
  • Sure follow the observer pattern, but isn't the difference just that you move the callback-adding code from the constructor into an own method? Please provide your implementation of Car. Commented Jul 31, 2013 at 14:47

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

3 Comments

You should avoid that unnecessary self variable, and move changeGear to the prototype.
@Bergi: actually, that function is just a sample to demonstrate.
@Bergi: I agree with you that the self variable in this case is redundant. Just I have a habit of using that variable to avoid this problem in javascript
1

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

4 Comments

i dont believe that does what i want it to do. I want the onGearCHanged to be triggered from within the class (when gears change).. something like function Car() { var that = this; this.onGearChanged = function(callback) { callback(); Uncaught TypeError: undefined is not a function }; setTimeout(that.onGearChanged, 2000); } var car = new Car(); car.onGearChanged(function(){ console.log("gear changed"); });
A method name onX indicates that you can set up a callback for an X event, not to trigger the callback. In your last example, you should rename addCallback to onGearChanged and onGearChanged to changeGear (and the other examples are not doing what was requested).
I changed the answer to make it look more like what you want (the only difference was that you trigger onGearChanged inside of the class). But that depends on your usecase. Do you know when onGearChanged must be called?
@Bergi ok, changed code to follow the naming convention, but the structure is the same

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.