Skip to content

Instantly share code, notes, and snippets.

@julik
Created October 8, 2025 10:14
Show Gist options
  • Save julik/e3e16d58c5e9bef0b1723d18c1d1d0ab to your computer and use it in GitHub Desktop.
Save julik/e3e16d58c5e9bef0b1723d18c1d1d0ab to your computer and use it in GitHub Desktop.
/*
Encapsulates a number of event handlers that should later
at some point be released. Useful for attaching blocks
of complex interactions to elements or to `document` and then detaching
them in bulk when the component/UI that they are serving is
unmounted or disconnected.
connect() {
this.evm = new EventListenerManager();
// ....
this.evm.add(document, "drag", (evt) => {
// ......
});
}
disconnect() {
this.evm.removeAll();
}
The usefulness is that usually one needs to add event listeners in bulk, and they
need to be wrapped with various throttle() and debounce() functors. When this is done,
a function with a new identity is created - and to remove these you need to preserve references
to these functions to be able to remove the event listeners at some point.
Since Turbolinks presents a "never reload" model by default it is primordial to manage
event listeners correctly and remove them when they are no longer required.
*/
class EventListenerManager {
constructor(...otherManagers) {
this.releaseFns = [];
this.nest(...otherManagers);
}
nest(...otherManagers) {
for (let mgr of otherManagers) {
this.releaseFns.push(() => mgr.removeAll());
}
}
add(target, event, handlerFn, options) {
target.addEventListener(event, handlerFn, options);
this.releaseFns.unshift(() => {
target.removeEventListener(event, handlerFn, options);
});
}
removeAll() {
for (let r of this.releaseFns) {
r();
}
this.releaseFns.length = 0;
}
}
export { EventListenerManager };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment