Md Shuvo
Md Shuvo

Reputation: 69

remove event listener without knowing what the call back function is

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?

Upvotes: 2

Views: 5929

Answers (3)

Ernesto Stifano
Ernesto Stifano

Reputation: 3130

As written in comments, 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 completely 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 comes 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.)

Upvotes: 5

Swapnil Soni
Swapnil Soni

Reputation: 1049

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.

Upvotes: 0

Md Shuvo
Md Shuvo

Reputation: 69

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')

Upvotes: 0

Related Questions