So I called a function with .bind() but later in my code I have to remove that eventListner.
EventTarget.addEventListener("click", myFunction.bind(null, arg))
So I called a function with .bind() but later in my code I have to remove that eventListner.
EventTarget.addEventListener("click", myFunction.bind(null, arg))
On
One could store/set each element specific bound handler function in/to a WeakMap by the element's reference itself, thus one easily can retrieve/get it again and e.g. un-register it.
function logEventWithBoundHandlerId({ type, currentTarget }) {
console.log({ type, currentTarget, bounId: this.id });
}
const handlerStorage = new WeakMap;
function registerAnyBoundHandler({ currentTarget }) {
document
.querySelectorAll('div button')
.forEach((elm, idx) => {
// create bound handler.
const handler = logEventWithBoundHandlerId.bind({ id: idx + 1 });
// add bound handler to storage (weak map)
// by element reference.
handlerStorage.set(elm, handler);
// add listener.
elm.addEventListener('click', handler);
});
currentTarget.parentNode.querySelector('[disabled]').disabled = false;
currentTarget.disabled = true;
}
function unregisterAnyBoundHandler({ currentTarget }) {
console.clear();
document
.querySelectorAll('div button')
.forEach(elm => {
// remove listener.
elm.removeEventListener('click', handlerStorage.get(elm));
// delete bound handler from storage (weak map)
// by element reference.
handlerStorage.delete(elm);
});
currentTarget.parentNode.querySelector('[disabled]').disabled = false;
currentTarget.disabled = true;
}
function init() {
const [ btnRegister, btnUnregister ] = document
.querySelectorAll('fieldset button');
btnRegister.addEventListener('click', registerAnyBoundHandler);
btnUnregister.addEventListener('click', unregisterAnyBoundHandler);
}
init();
body { margin: 0; }
fieldset { margin: 0 0 5px 0; padding: 5px 3px; }
div { padding-left: 4px; }
.as-console-wrapper { max-height: 65%!important; top: auto; }
<fieldset>
<button>register any bound handler</button>
<button disabled>unregister any bound handler</button>
</fieldset>
<div>
<button>click 1</button>
<button>click 2</button>
<button>click 3</button>
</div>
The same storage approach has to be followed in case one chooses to utilize the AbortController and AbortSignal Web APIs.
function logEventWithBoundHandlerId({ type, currentTarget }) {
console.log({ type, currentTarget, bounId: this.id });
}
const controllerStorage = new WeakMap;
function registerAnyBoundHandler({ currentTarget }) {
document
.querySelectorAll('div button')
.forEach((elm, idx) => {
// create element specific abort controller.
const controller = new AbortController;
// add element specific controller to storage
// (weak map) by the very element's reference.
controllerStorage.set(elm, controller);
// add listener with the `signal` option.
elm.addEventListener(
'click',
logEventWithBoundHandlerId.bind({ id: idx + 1 }),
{ signal: controller.signal },
);
});
currentTarget.parentNode.querySelector('[disabled]').disabled = false;
currentTarget.disabled = true;
}
function unregisterAnyBoundHandler({ currentTarget }) {
console.clear();
document
.querySelectorAll('div button')
.forEach(elm => {
// retrieve element specific controller.
const controller = controllerStorage.get(elm);
// abort controller.
controller.abort();
// delete element specific controller from
// storage (weak map) by element reference.
controllerStorage.delete(elm);
});
currentTarget.parentNode.querySelector('[disabled]').disabled = false;
currentTarget.disabled = true;
}
function init() {
const [ btnRegister, btnUnregister ] = document
.querySelectorAll('fieldset button');
btnRegister.addEventListener('click', registerAnyBoundHandler);
btnUnregister.addEventListener('click', unregisterAnyBoundHandler);
}
init();
body { margin: 0; }
fieldset { margin: 0 0 5px 0; padding: 5px 3px; }
div { padding-left: 4px; }
.as-console-wrapper { max-height: 65%!important; top: auto; }
<fieldset>
<button>register any bound handler</button>
<button disabled>unregister any bound handler</button>
</fieldset>
<div>
<button>click 1</button>
<button>click 2</button>
<button>click 3</button>
</div>
No reason to use .bind for this use-case, instead use a modern AbortController signal:
And then whenever you need to clean up that event listener:
And done. The JS engine will know what to do, no need for removeEventListener with the same arguments as you used for addEventListener.