Lets say we add a even listener to a button like this
function handler(){
alert(0)
}
btn.addEventListener("click", handler)
now if we want to remove event listener we can simply do:
btn.removeEventListener("click", handler)
but what if we don't have access to the handler function. for example, some third-party library is attaching an event listener to an element and I want to remove it. how can we do so?
Lets say we add a even listener to a button like this
function handler(){
alert(0)
}
btn.addEventListener("click", handler)
now if we want to remove event listener we can simply do:
btn.removeEventListener("click", handler)
but what if we don't have access to the handler function. for example, some third-party library is attaching an event listener to an element and I want to remove it. how can we do so?
Share Improve this question asked Aug 26, 2021 at 12:42 Md ShuvoMd Shuvo 693 silver badges9 bronze badges 7- 2 You cannot remove it without the handler/original function reference. – evolutionxbox Commented Aug 26, 2021 at 12:43
- 3 Only way to remove event listeners is to recreate the element – epascarello Commented Aug 26, 2021 at 12:45
-
2
Probably you should look into
third-party library
documentation and see if there is any remove event. – ikhvjs Commented Aug 26, 2021 at 12:45 -
1
btn.replaceWith(btn.cloneNode(true));
sure there are duplicates with that answer – epascarello Commented Aug 26, 2021 at 12:49 - @epascarello just answered with a possible alternative that will not remove the event listeners, but should prevent third-party listeners from firing. – Ernesto Stifano Commented Aug 26, 2021 at 13:27
3 Answers
Reset to default 5As written in ments, you can't remove an event listener without having the callback reference unless you re-create/clone that element, which can be problematic sometimes and also does not seem to be good practice or particularly performant (Spoiler Alert - None of the possible solutions can be pletely considered good practice because your situation isn't ideal from the beginning).
As an alternative, you can try something like this:
element.addEventListener('click', (e) => {
e.stopImmediatePropagation();
e.stopPropagation();
}, true);
Odds are that your third-party library will be listening to the event on the bubbling
phase. If so, doing this on the capture
phase (see addEventListener
third argument) will prevent your third-party listeners from firing.
Please note that this will break event propagation at the capture
phase. This means that any listener set on the bubbling
phase for that event, triggered on that element or any of its children will not fire. Also the remaining listeners on the capture
phase will not fire either.
Leveraging Event's Nature
If you add the above event listener before your third-party library adds its own event listeners, you can be "more sure" that yours will be fired first.
Please consider that capture
phase listeners will ALWAYS be fired before bubbling
phase listeners and that element's DOM order will ALWAYS be respected.
What is a bit unpredictable is the execution order for multiple listeners for the same event on the same phase and on the same target element. See Event Order.
With that being said, if you add the above listener to the PARENT of your interested element, you can be 99% sure that your third-party library listener will not be executed and this es with almost zero performance impact. (The remaining 1% is for the case in which the library somehow adds an event listener on the capture
phase and on a previous ancestor than yours, that could also be the window
object).
If you want to still fire listeners for the parent element you can filter out cases using event.target
property.
Something like:
parent.addEventListener('click', (e) => {
if (element.contains(e.target)) {
e.stopPropagation();
}
}, true);
Final Note
I took the time to write all this more as a didactic example about DOM events than as an actual working solution. This is because any possible solution that I can think about right now will have some kind of drawback, issue or limitation (performance, debugging, unpredictability, etc.)
This is what I tried(It didnt work tho)
function removeEListener(element, event){
let listeners = getEventListeners(element)[event]
try{
listeners.forEach(listener => {
listener.remove()
element.removeEventListener(event, listener.listener, listener.useCapture)
})
}catch(e){
console.log(e)
}
}
removeEListener(document.querySelector(".btn"), 'click')
A simpler way is to clone node and its child elements to remove all the listeners.
function recreateNode(el, withChildren) {
if (withChildren) {
el.parentNode.replaceChild(el.cloneNode(true), el);
}
else {
var newEl = el.cloneNode(false);
while (el.hasChildNodes()) newEl.appendChild(el.firstChild);
el.parentNode.replaceChild(newEl, el);
}
}
Here withChildren: true
will replace all nested elements as well.
With your question, You don't need to find out the reference function.