51

In this es6 script, the click event don't works because sayHello method is called with this.elm (<div>) as this.

how to associate a event to a method without loose the scope?

class player{
  constructor (name) {
    this.name = name;
    this.elm = document.createElement('div');
    this.elm.addEventListener('click', this.sayHello);
  }
  sayHello() {
    console.log(this.name + ' say: "hello!"'); // 'undefined say 'hello!"';
  }
  kill() {
    console.log(`RIP ${this.name} :'(`); 
    this.elm.addClass('dead');
    this.elm.removeEventListener('click', this.sayHello);
  }
}
0

1 Answer 1

128

This is a general JS issue, but the core of it is that

this.elm.addEventListener('click', this.sayHello);

is no different than

var fn = this.sayHello;
this.elm.addEventListener('click', fn);

You are passing a function as the event handler, but have not ensured that when fn is called that this will be set to your desired value. The easiest way to do this in ES5 would be

this.elm.addEventListener('click', this.sayHello.bind(this));

or in ES6, using an arrow function:

this.elm.addEventListener('click', evt => this.sayHello(evt));

Note however that both of these solutions will break your (already slightly broken) logic in kill because

this.elm.removeEventListener('click', /* what? */);

You don't have any reference to the function that you attached anymore, so you have no way of removing the event handler.

I'd suggest two options:

// Create a new function that is bound, and give it a new name
// so that the 'this.sayHello()' call still works.
this.boundSayHello = evt => this.sayHello(evt);
this.elm.addEventListener('click', this.boundSayHello);
this.elm.removeEventListener('click', this.boundSayHello);

or

// Bind the function with the same name and use `.bind` instead of the
// arrow function option.
this.sayHello = this.sayHello.bind(this);
this.elm.addEventListener('click', this.sayHello);
this.elm.removeEventListener('click', this.sayHello);
3
  • 1
    thank, it's what I use, but each object need to have a object pointing on each binded function needed as callback codepen.io/yukulele/pen/yNVVxV/?editors=001
    – Yukulélé
    Commented May 27, 2015 at 13:45
  • Great! I prefer the first solution. First I tried .bind(this) but then it failed when trying to get other variables inside the this scope because I was inside an ES6 class. Commented Jan 1, 2019 at 21:28
  • Ah so canvas.addEventListener('mousedown', pad_mouseDown, false); in ES6 class style will be this.canvas.addEventListener('mousedown', evt=> this.pad_mouseDown(evt), false); Commented Feb 7, 2019 at 7:48

Not the answer you're looking for? Browse other questions tagged or ask your own question.