removeEventListener without knowing the function
Asked Answered
P

4

47

Some of the third party plugin will attach the eventListener into the site. How to I remove the eventListener without knowing the function that attached.

I refer this removeEventListener but I can't get any clue to remove this.

Eg: getEventListeners(window) shows the events attached. But, when I try to remove the event using window.removeEventListener("eventname") is not working without knowing that function.

Please help, Thanks in advance.

Pannell answered 10/11, 2014 at 14:0 Comment(1)
See also the different answers on this related question (I posted an answer also): #4386800Crinite
E
31

getEventListeners(window) will return a map of events and their registered event listeners.

So for DOMContentLoaded event for example you can have many event listeners. If you know the index of the listener you want to remove (or if there exists only one), you can do:

var eventlistener = getEventListeners(window)["DOMContentLoaded"][index];
window.removeEventListener("DOMContentLoaded", 
                           eventlistener.listener,
                           eventlistener.useCapture);
Extensive answered 10/11, 2014 at 14:14 Comment(11)
Even more convenient because it also returns deregistration function remove: getEventListeners(window).DOMContentLoaded[0].remove().Conditional
@dfsq, chrome yes, but not firefox. (can't test for ie).Extensive
@Pannell That's not implemented in every browsers and is not part of the spec. That shouldn't be the accepted answer, unless your question targets Chrome only. In this case it should be stated in the question.Macon
@Macon Yes I know about that. I will definetly find the answer for all the browser. I accepted this answer because it gives some clue.Pannell
@Pannell Well, that is confusing for every other people that will look at this question. The correct answer was already given below by jAndy.Macon
@plalx, it works in chrome and firefox (remove() does not work in firefox)Extensive
@Extensive A feature that is not in the spec and cannot be emulated/shimmed in all browsers is not to be used anywhere in my opinion. What about IE? You must code for the standards...Macon
@plalx, you are right in the absolute, but it can help in resolving some situation. Should I delete the answer, I don't think so. Should the Op change the accepted answer, that's his decision to make. Saying that there is no way to do this, is also not true. And IE will catch up to this someday.Extensive
getEventListeners(window) does not work in Android 4.4 WebViews which are stuck on Chrome 33. Chromium bug 336472 was supposedly fixed in time for Chrome 33 but apparently the fix did not make it as far as Android WebViews. More recent versions of Chrome will take getEventListeners(window). The old version only takes getEventListeners(document), which doesn't usually cover events like scroll :-(Fiasco
No such method in Firefox, still. This shouldn't be an accepted solution.Brayer
For Firefox, you can use a polyfill, see github.com/colxi/getEventListeners/issues/1.Crinite
A
14

Unfortunately, you cannot do that. You need to have a reference to the event handler function in order to remove it by removeEventListener.

Your only option if you cannot get that reference would be by entirely replacing that Node.

Ardenia answered 10/11, 2014 at 14:6 Comment(7)
jAndy is there any way to get that reference via jquery or javascript. Because that event is added by thirdparty and that event is attached in window elementPannell
@Pannell AFAIK there isn't (but hopefully some Ninja will correct me here if I'm wrong). Natively added events via addEventListener are not stored anywhere accessible by Javascript.Ardenia
@Pannell Could you explain why you are trying to do that instead? If the third-party code added the listener, it's because it probably needs it to do it's work properly...Macon
@Ardenia Unless the third-party's code stored the listener functions, like the code should be doing, so that plugins can be properly destroyed or un-applied. However, these references could be hidden within unaccessible scopes...Macon
Actually it is possible with getEventListeners, since it holds event listeners functions.Conditional
@Ardenia Because it prevent all the other events before it fired even after close that popup plugin.Pannell
I'd add that not being able to do that, makes that API utterly brilliant. Imagine if some horrible library could wreck all of your listeners?Ashly
C
1

Caveat: Uses browser specific getEventListeners, which is available in Chrome and Edge.

If you need to remove all event listeners:

// selector is optional - defaults to all elements including window and document
// Do not pass window / document objects. Instead use pseudoselectors: 'window' or 'document'
// eTypeArray is optional - defaults to clearing all event types
function removeAllEventListeners(selector = '*', eTypeArray = ['*']) {
  switch (selector.toLowerCase()) {
    case 'window':
      removeListenersFromElem(window);
      break;
    case 'document':
      removeListenersFromElem(document);
      break;
    case '*':
      removeListenersFromElem(window);
      removeListenersFromElem(document);
    default:
      document.querySelectorAll(selector).forEach(removeListenersFromElem);
  }
  
  function removeListenersFromElem(elem) {
    let eListeners = getEventListeners(elem);
    let eTypes = Object.keys(eListeners);
    for (let eType of inBoth(eTypes, eTypeArray)) {
      eListeners[eType].forEach((eListener)=>{
        let options = {};
        inBoth(Object.keys(eListener), ['capture', 'once', 'passive', 'signal'])
          .forEach((key)=>{ options[key] = eListener[key] });
        elem.removeEventListener(eType, eListener.listener, eListener.useCapture);
        elem.removeEventListener(eType, eListener.listener, options);
      });
    }
  }

  function inBoth(arrA, arrB) {
    setB = new Set(arrB);
    if (setB.has('*')) {
      return arrA;
    } else {
      return arrA.filter(a => setB.has(a));
    }
  }
}

Use:

removeAllEventListeners('a.fancyLink'); // remove all event types
removeAllEventListeners('a.fancyLink', ['click', 'hover']); // remove these types
removeAllEventListeners('*', ['click', 'hover']); // remove these types everywhere
removeAllEventListeners(); // remove everything you can

Note, this may not always work. Per MDN:

It's worth noting that some browser releases have been inconsistent on this, and unless you have specific reasons otherwise, it's probably wise to use the same values used for the call to addEventListener() when calling removeEventListener().

My use of options tries to deal with this issue by hopefully calling removeEventListener with the same values used when the listener was added.

Cranky answered 27/6, 2023 at 15:0 Comment(0)
P
-1

Update: 2023

EventListeners can be removed without knowing the actual function reference. But it will only work in modern browsers.

Use AbortController to remove the event. With AbortSignal, you can simply get the signal to remove it for you:

Sample Code:

const controller = new AbortController();
const { signal } = controller;

window.addEventListener('resize', () => doSomething(), { signal });

controller.abort(); // It wll remove the "resize" event handler.

You can check and add a polyfill for older browsers

Pannell answered 7/1, 2023 at 3:45 Comment(1)
This will remove the event listener you just added. But only that one, so it's only usable if it is you adding the event listener in the first place. But if you are adding the event listener then you might as well just keep a ref to the function and do a normal remove.Monikamoniker

© 2022 - 2024 — McMap. All rights reserved.