TIL – addEventListener accepts functions and (!) objects
To build interactive web interfaces, you have to use DOM (Document Object Model) events. How does that usually work?
You define the event type you're interested in, pair it with a callback function and you are ready to react to clicks, keypresses, scrolls and many other events.
For example, to react to a button click, the following code can be used:
document.querySelector('button')
.addEventListener('click', () => {
console.log('element clicked');
});
The code queries the DOM, grabs a specific element and adds a click
event listener to it using addEventListener
.
According to MDN, target.addEventListener
defines the following parameters:
target.addEventListener(type, listener [, options]);
target.addEventListener(type, listener [, useCapture]);
target.addEventListener(type, listener [, useCapture, wantsUntrusted ]); // Gecko/Mozilla only
addEventListener
accepts the event type, a listener
callback function and an options
or useCapture
parameter.
What if I told you, that the listener
parameter can be a function but also an object?
addEventListener
and the EventListener
interface
It turns out that MDN defines listener
as the following:
[listener] must be an object implementing the EventListener interface, or a JavaScript function.
The early DOM events specification (we're talking pre-HTML5 here) defined an EventListener
interface. Objects implementing the interface (they had to define a handleEvent
method) where valid to be passed to the addEventListener
method.
// a class implementing
// the `EventListener` interface
class EventHandler {
constructor() {
this.eventCount = 0;
}
handleEvent() {
this.eventCount++;
console.log(`Event triggered ${this.eventCount} time(s)`);
}
}
document.querySelector('button')
.addEventListener('click', new EventHandler());
The code above uses a JavaScript class EventHandler
. Initialized event handler objects can be passed to addEventHandler
and they keep track of the number of times a specific event occurred (check it on CodePen). All information is stored in the object itself, and the code works without any out of scope variables. I like this pattern and I can see it come in handy when dealing with sequential events.
According to MDN, the EventListener
interface is supported by all major browsers and you can safely pass objects implementing it to addEventListener
.
When would you pass EventListener
objects to addEventListener
? I'd love to learn about more examples!