When it comes to using a plain old event listener in your Aurelia applications, if you are not aware of how classes work and how things get transpiled, then you will most likely run into some issues working with events and scope.
First you might try something like the following:
export MyClass {
attached() {
document.addEventListener('click', this.handleBodyClick);
}
detached() {
document.removeEventListener('click', this.handleBodyClick);
}
handleBodyClick(e) {
console.log(e.target);
}
}
On the surface everything looks fine, it should work right? Sorry, but this will not work. Many first timers implementing event listeners into their apps will run into this, heck I even ran into it once as well.
The scope of the callback function in this instance due to how event listeners work will not be the current class. So you will lose reference to the current class scope, the value of this becomes that of the outer function that created it or something like that.
The right away to attach event listeners in Aurelia:
export MyClass {
constructor() {
this.handleBodyClick = e => {
console.log(e.target);
};
}
attached() {
document.addEventListener('click', this.handleBodyClick);
}
detached() {
document.removeEventListener('click', this.handleBodyClick);
}
}
Worth pointing out here is that you should always attach your events in the Aurelia attached
lifecycle method and detach them in the detached
lifecycle method.
While the thought of creating a function in your constructor might make some cringe, due to the way event listeners work as per the spec, there is really no other choice.
You might be able to use bind on your addEventListener
like this this.handleBodyClick.bind(this)
but bind
can introduce issues into your app and arrow functions are arguably the way to go.
what issues are introduced by bind ? Also, the bind notation would keep code cleaner, as the callback function could be declared statically in the class, and not created dynamically inside the constructor
Creating new function in attached requires you to keep a reference to it to remove listener in detached, I think that’s the problem.
But i don’t know how to create handler statically without binding.
What about using ‘() => {}’ (lambda) syntax? I’m not sure about ECMA script but in typescript works really well and persists scope – it doesn’t compile to .bind, it creates a local copy of this as _this and uses that.
example:
attached() {
window.addEventListener(“load”, e => this.eventHandler(e));
}
Awesome work Dwayne, keep up the good work!