Is there a proper way to handle setting up event listeners in a class such that it preserves this
?
This is similar to Binding vs Arrow-function (in JavaScript, or for react onClick) but for vanilla event handlers instead of react, and the methods they use don’t work for private methods
- Use bind
this.#myelem.addEventListener("click",this.#onclick1.bind(this));`
- Use arrow functions
this.#myelem.addEventListener("click",(event)=>this.#onclick2(event));
- Pre-binding the function in the constructor, however this only works with public
methods and not private ones
class MyClass {
#elem;
constructor() {
this.#elem = /*...*/;
this.onclick4 = this.onclick.bind(this);
//doesn't work with private vars
//Error: cannot assign to private method
//this.#onclick = this.#onclick.bind(this);
this.#elem.addEventListener("click",this.onclick);
}
onclick(event) {/*...*/}
}
- Creating a class level arrow function
class MyClass{
constructor() {
this.#elem = /*...*/;
this.#elem.addEventListener("click",this.#onclick);
}
this.#onclick = (event) => {/*...*/}
}
The above answer compares 3 and 4 mentioning that 4 has higher memory usage that 3,
however 3 doesn’t work with private methods. Is there one of these options, or
an option I don’t have here that is better? Are they all close enough that the choice
should be based on style and not on performance?
class MyClass {
constructor()
{
this.onclick4 = this.onclick4.bind(this);
//Error: cannot assign to private method
//this.#onclick5 = this.#onclick5.bind(this);
document.getElementById("elem1").addEventListener("click",this.#onclick1.bind(this));
document.getElementById("elem2").addEventListener("click",(event)=>this.#onclick2(event));
document.getElementById("elem3").addEventListener("click",this.#onclick3);
document.getElementById("elem4").addEventListener("click",this.onclick4);
//document.getElementById("elem5").addEventListener("click",this.#onclick5);
}
#onclick1(event) { this.#print("1 was clicked"); }
#onclick2(event) { this.#print("2 was clicked"); }
#onclick3 = (event) => { this.#print("3 was clicked"); }
onclick4(event) { this.#print("4 was clicked"); }
#onclick5(event) { this.#print("5 was click"); }
#print(str)
{
console.log(str);
}
}
let mc = new MyClass();
<button id="elem1">btn1</button>
<button id="elem2">btn2</button>
<button id="elem3">btn3</button>
<button id="elem4">btn4</button>
<button id="elem4">btn5</button>