Search code examples
javascriptjqueryslickgrid

Calling a function bound to an event from another function bound to an event isn't working


I'm making a custom editor for slickgrid, although I doubt what I'm doing really matters in this case. So let's say I have something like this vaguely setup:

function TestEditor(args) {
 var $test0, $test1;
 //other variables

 this.init = function () {
  //various init stuff, it all works fine
  //init $test0 and $test1, also works fine

  $test0.bind("change", this.test0Changed);
  $test1.bind("change", this.test1Changed);

  this.test0Changed(); //this works fine too, makes the nested call to test1Changed
 }

 this.test0Changed = function() {
  //does various operations
  this.test1Changed(); //calls test1Changed, this works _unless_ test0Changed is called through an event, then the code breaks here!
  //stuff that won't happen when the code breaks at the previous call
 }

 this.test1Changed = function() {
  //stuff, works fine unless called by test0Changed triggered by an event, then nothing
 }

 //whatever, lots of other stuff, it all works

 this.init();
}

I want test0Changed to make a call to test1Changed, and it works fine if I explicitly make the call myself to this.test0Changed() in the code. But when test0Changed is triggered by the 'change' event, the code breaks when it tries to call this.test1Changed(). If I comment out the call to this.test1Changed(), everything is fine, so I know it's that precise line that is causing the problem. What is causing this?


Solution

  • It's because when you the function to .bind(), it doesn't "remember" the intial this value.

    As a handler, this will be the element that received the event.

    this.init = function () {
    
       var self = this;
    
       $test0.bind("change", function() {self.test0Changed.apply(self, arguments);});
       $test1.bind("change", function() {self.test1Changed.apply(self, arguments);});
    
     }
    

    Here I referenced the this you want to use in a variable, and I passed anonymous functions that use that referenced this value to call the functions.


    I also used .apply to ensure that all the original arguments are passed on. If that isn't necessary, you could change it to this...

    this.init = function () {
    
       var self = this;
    
       $test0.bind("change", function() {self.test0Changed();});
       $test1.bind("change", function() {self.test1Changed();});
    
     }
    

    Or you could use jQuery's $.proxy to retain the this value...

    this.init = function () {
    
       $test0.bind("change", $.proxy(this, 'test0Changed'));
       $test1.bind("change", $.proxy(this, 'test1Changed'));
    
     }