4

I have a class and in the init method I'm setting up a click event, and inside that event I want to call a method on the class and I can't figure out how to do it or if it's even possible. Here's code that shows the structure of what I'm trying. in the classes init() function, after the ajax returns I'm setting up a click event, and in that callback I want to call the class's classFn() function. I've tried binding this, I've tried self = this and binding that, arrow functions (which I didn't expect to work but figured I'd give it a try), etc.

class MyClass {
  constructor() {
   this.a = '';
  }

  init() {
    ....
    $.getJSON(url, function(data) {
      $(mySelector).click(function() {
        classFn();
      });
    });
  }

  classFn() {
    ....
  }
}
kombat
  • 343
  • 5
  • 16

2 Answers2

9

function changes the meaning of this. One way to fix the problem is to use bind. However, you'd have to use it twice, because you have two layers of function. A simple way to solve it is to use arrow functions, which do not change this:

class MyClass {
  constructor() {
   this.a = '';
  }

  init() {
    ....
    $.getJSON(url, (data) => {
      $(mySelector).click(() => {
        this.classFn();
      });
    });
  }

  classFn() {
    ....
  }
}
Aurel Bílý
  • 7,068
  • 1
  • 21
  • 34
  • The arrow functions don't work. I put bind in multiple places and that works. That's what I was missing: multiple binds. Once it was working, I wanted to start from the inside out converting them to arrow functions. But on the first one it fails. In the event callback, this is still bound to the clicked element. Is it possible that when an arrow function is used as a function argument that the "lexically surrounding code" may not be what we think it is? I also figured out that making the method static and calling it with MyClass.classFn() will work as well. – kombat Feb 15 '18 at 16:55
  • @kombat Ah, no it's nothing to do with "lexically surrounding code". It is because jQuery makes sure to `bind` the function you give as a callback, so that `this` (or `$(this)`) refer to the element. See e.g. https://api.jquery.com/click/ (the examples section at the bottom) My bad. – Aurel Bílý Feb 15 '18 at 20:10
1

You need to bind the callback function and call like this.classFn(). You could either use .bind or arrow function

class MyClass {
  constructor() {
   this.a = '';
   this.init = this.init.bind(this);
  }

  init() {
    ....
    $.getJSON(url, function(data) {
      $(mySelector).click(function() {
        this.classFn();
      }.bind(this));
    }.bind(this));
  }

  classFn() {
    ....
  }
}

or

class MyClass {
  constructor() {
   this.a = '';
  }

  init = ()  => {   // class fields are stage-2 proposal with es6
    ....
    $.getJSON(url,(data) =>  {
      $(mySelector).click(()  => {
        this.classFn();
      });
    });
  }

  classFn() {
    ....
  }
}
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400