If you’re using Stimulus or modern JavaScript classes, you’ve probably hit this:
import { Controller } from '@hotwired/stimulus'
export default class extends Controller {
connect() {
this.element.addEventListener("click", this.clicked)
}
clicked() {
console.log(this) // Window?! It should be the controller.
}
}
JavaScript loves to mess with this, and in this case, it’s pointing to window, not your controller.
The usual advice is to bind your method in connect():
connect() {
this.clicked = this.clicked.bind(this)
this.element.addEventListener("click", this.clicked)
}
Sure, it works. But also… ew.
Here’s what I prefer — define the method as an arrow function:
clicked = () => {
console.log(this) // Controller instance 🎉
}
Now connect() stays nice and clean, like we originally intended:
connect() {
this.element.addEventListener("click", this.clicked)
}
No binding. No surprises. It just works.™