Javascript/DOM: How to remove all event listeners of a DOM object?

JavascriptEventsDom

Javascript Problem Overview


Just question: Is there any way to completely remove all events of an object, e.g. a div?

EDIT: I'm adding per div.addEventListener('click',eventReturner(),false); an event.

function eventReturner() {
    return function() {
        dosomething();
    };
}

EDIT2: I found a way, which is working, but not possible to use for my case:

var returnedFunction;
function addit() {
    var div = document.getElementById('div');
    returnedFunction = eventReturner();
    div.addEventListener('click',returnedFunction,false); //You HAVE to take here a var and not the direct call to eventReturner(), because the function address must be the same, and it would change, if the function was called again.
}
function removeit() {
    var div = document.getElementById('div');
    div.removeEventListener('click',returnedFunction,false);
}

Javascript Solutions


Solution 1 - Javascript

I am not sure what you mean with remove all events. Remove all handlers for a specific type of event or all event handlers for one type?

Remove all event handlers

If you want to remove all event handlers (of any type), you could clone the element and replace it with its clone:

var clone = element.cloneNode(true);

Note: This will preserve attributes and children, but it will not preserve any changes to DOM properties.


Remove "anonymous" event handlers of specific type

The other way is to use removeEventListener() but I guess you already tried this and it didn't work. Here is the catch:

> Calling addEventListener to an anonymous function creates a new listener each time. Calling removeEventListener to an anonymous function has no effect. An anonymous function creates a unique object each time it is called, it is not a reference to an existing object though it may call one. When adding an event listener in this manner be sure it is added only once, it is permanent (cannot be removed) until the object it was added to, is destroyed.

You are essentially passing an anonymous function to addEventListener as eventReturner returns a function.

You have two possibilities to solve this:

  1. Don't use a function that returns a function. Use the function directly:

     function handler() {
         dosomething();
     }
    
     div.addEventListener('click',handler,false);
    
  2. Create a wrapper for addEventListener that stores a reference to the returned function and create some weird removeAllEvents function:

     var _eventHandlers = {}; // somewhere global
     
     const addListener = (node, event, handler, capture = false) => {
       if (!(event in _eventHandlers)) {
         _eventHandlers[event] = []
       }
       // here we track the events and their nodes (note that we cannot
       // use node as Object keys, as they'd get coerced into a string
       _eventHandlers[event].push({ node: node, handler: handler, capture: capture })
       node.addEventListener(event, handler, capture)
     }
    
     const removeAllListeners = (targetNode, event) => {
       // remove listeners from the matching nodes
       _eventHandlers[event]
         .filter(({ node }) => node === targetNode)
         .forEach(({ node, handler, capture }) => node.removeEventListener(event, handler, capture))
    
       // update _eventHandlers global
       _eventHandlers[event] = _eventHandlers[event].filter(
         ({ node }) => node !== targetNode,
       )
     }
    

And then you could use it with:

    addListener(div, 'click', eventReturner(), false)
    // and later
    removeAllListeners(div, 'click')

DEMO

Note: If your code runs for a long time and you are creating and removing a lot of elements, you would have to make sure to remove the elements contained in _eventHandlers when you destroy them.

Solution 2 - Javascript

This will remove all listeners from children but will be slow for large pages. Brutally simple to write.

element.outerHTML = element.outerHTML;

Solution 3 - Javascript

Use the event listener's own function remove(). For example:

getEventListeners().click.forEach((e)=>{e.remove()})

Solution 4 - Javascript

As corwin.amber says, there are differences between Webkit an others.

In Chrome:

getEventListeners(document);

Which gives you an Object with all the existing event listeners:

Object 
 click: Array[1]
 closePopups: Array[1]
 keyup: Array[1]
 mouseout: Array[1]
 mouseover: Array[1]
 ...

From here you can reach the listener you want to remove:

getEventListeners(document).copy[0].remove();

So All the event listeners:

for(var eventType in getEventListeners(document)) {
   getEventListeners(document)[eventType].forEach(
      function(o) { o.remove(); }
   ) 
}

In Firefox

Is a little bit different because it uses a listener wrapper that contains no remove function. You have to get the listener you want to remove:

document.removeEventListener("copy", getEventListeners(document).copy[0].listener)

All the event listeners:

for(var eventType in getEventListeners(document)) {
  getEventListeners(document)[eventType].forEach(
    function(o) { document.removeEventListener(eventType, o.listener) }
  ) 
}

I stumbled with this post trying to disable the annoying copy protection of a news website.

Enjoy!

Solution 5 - Javascript

You can add a hook function to intercept all calls to addEventHandler. The hook will push the handler to a list that can be used for cleanup. For example,

if (EventTarget.prototype.original_addEventListener == null) {
    EventTarget.prototype.original_addEventListener = EventTarget.prototype.addEventListener;

    function addEventListener_hook(typ, fn, opt) {
        console.log('--- add event listener',this.nodeName,typ);
        this.all_handlers = this.all_handlers || [];
        this.all_handlers.push({typ,fn,opt});
        this.original_addEventListener(typ, fn, opt);  
    }

    EventTarget.prototype.addEventListener = addEventListener_hook;
}

You should insert this code near the top of your main web page (e.g. index.html). During cleanup, you can loop thru all_handlers, and call removeEventHandler for each. Don't worry about calling removeEventHandler multiple times with the same function. It is harmless.

For example,

function cleanup(elem) {
    for (let t in elem) if (t.startsWith('on') && elem[t] != null) {
        elem[t] = null;
        console.log('cleanup removed listener from '+elem.nodeName,t);
    } 
    for (let t of elem.all_handlers || []) {
        elem.removeEventListener(t.typ, t.fn, t.opt);
        console.log('cleanup removed listener from '+elem.nodeName,t.typ);
    } 
}

Note: for IE use Element instead of EventTarget, and change => to function, and various other things.

Solution 6 - Javascript

you can add function and remove all other click by assign them

btn1 = document.querySelector(".btn-1")
btn1.addEventListener("click" , _=>{console.log("hello")})
btn1.addEventListener("click" , _=>{console.log("How Are you ?")})

btn2 = document.querySelector(".btn-2")
btn2.onclick = _=>{console.log("Hello")}
btn2.onclick = _=>{console.log("Bye")}

<button class="btn-1">Hello to Me</button>
<button class="btn-2">Hello to Bye</button>

Solution 7 - Javascript

To complete the answers, here are real-world examples of removing events when you are visiting websites and don't have control over the HTML and JavaScript code generated.

Some annoying websites are preventing you to copy-paste usernames on login forms, which could easily be bypassed if the onpaste event was added with the onpaste="return false" HTML attribute. In this case we just need to right click on the input field, select "Inspect element" in a browser like Firefox and remove the HTML attribute.

However, if the event was added through JavaScript like this:

document.getElementById("lyca_login_mobile_no").onpaste = function(){return false};

We will have to remove the event through JavaScript also:

document.getElementById("lyca_login_mobile_no").onpaste = null;

In my example, I used the ID "lyca_login_mobile_no" since it was the text input ID used by the website I was visiting.

Another way to remove the event (which will also remove all the events) is to remove the node and create a new one, like we have to do if addEventListener was used to add events using an anonymous function that we cannot remove with removeEventListener. This can also be done through the browser console by inspecting an element, copying the HTML code, removing the HTML code and then pasting the HTML code at the same place.

It can also be done faster and automated through JavaScript:

var oldNode = document.getElementById("lyca_login_mobile_no");
var newNode = oldNode.cloneNode(true);
oldNode.parentNode.insertBefore(newNode, oldNode);
oldNode.parentNode.removeChild(oldNode);

Update: if the web app is made using a JavaScript framework like Angular, it looks the previous solutions are not working or breaking the app. Another workaround to allow pasting would be to set the value through JavaScript:

document.getElementById("lyca_login_mobile_no").value = "username";

At the moment, I don't know if there is a way to remove all form validation and restriction events without breaking an app written entirely in JavaScript like Angular.

Solution 8 - Javascript

You can indeed remove all event handlers by cloning the node as @FelixKling suggests in his answer, however don't forget that

attribute event handlers are not affected by cloning

Having element like this

<div id="test" onclick="alert(42)">test</div>

will still alert on click after cloning. To remove this sort of events, you need to use removeAttribute method, in general

const removeAttEvents = el =>
    [...el.attributes].forEach(att =>
        att.name.startsWith("on") && el.removeAttribute(att.name)
    );

Then having the test element above, calling removeAttEvents(test) gets rid of the click handler.

Solution 9 - Javascript

Removing all the events on document:

One liner:

for (key in getEventListeners(document)) { getEventListeners(document)[key].forEach(function(c) { c.remove() }) }

Pretty version:

for (key in getEventListeners(document)) {
  getEventListeners(document)[key].forEach(function(c) {
    c.remove()
  })   
}

Solution 10 - Javascript

angular has a polyfill for this issue, you can check. I did not understand much but maybe it can help.

const REMOVE_ALL_LISTENERS_EVENT_LISTENER = 'removeAllListeners';

    proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER] = function () {
        const target = this || _global;
        const eventName = arguments[0];
        if (!eventName) {
            const keys = Object.keys(target);
            for (let i = 0; i < keys.length; i++) {
                const prop = keys[i];
                const match = EVENT_NAME_SYMBOL_REGX.exec(prop);
                let evtName = match && match[1];
                // in nodejs EventEmitter, removeListener event is
                // used for monitoring the removeListener call,
                // so just keep removeListener eventListener until
                // all other eventListeners are removed
                if (evtName && evtName !== 'removeListener') {
                    this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, evtName);
                }
            }
            // remove removeListener listener finally
            this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, 'removeListener');
        }
        else {
            const symbolEventNames = zoneSymbolEventNames$1[eventName];
            if (symbolEventNames) {
                const symbolEventName = symbolEventNames[FALSE_STR];
                const symbolCaptureEventName = symbolEventNames[TRUE_STR];
                const tasks = target[symbolEventName];
                const captureTasks = target[symbolCaptureEventName];
                if (tasks) {
                    const removeTasks = tasks.slice();
                    for (let i = 0; i < removeTasks.length; i++) {
                        const task = removeTasks[i];
                        let delegate = task.originalDelegate ? task.originalDelegate : task.callback;
                        this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options);
                    }
                }
                if (captureTasks) {
                    const removeTasks = captureTasks.slice();
                    for (let i = 0; i < removeTasks.length; i++) {
                        const task = removeTasks[i];
                        let delegate = task.originalDelegate ? task.originalDelegate : task.callback;
                        this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options);
                    }
                }
            }
        }
        if (returnTarget) {
            return this;
        }
    };

....

Solution 11 - Javascript

You can add a helper function that clears event listener for example

function clearEventListener(element) {
 const clonedElement = element.cloneNode(true);
element.replaceWith(clonedElement);
return clonedElement;
}

just pass in the element to the function and that's it...

Solution 12 - Javascript

May be the browser will do it for you if you do something like:

Copy the div and its attributes and insert it before the old one, then move the content from the old to the new and delete the old?

Solution 13 - Javascript

Chrome only

As I'm trying to remove an EventListener within a Protractor test and do not have access to the Listener in the test, the following works to remove all event listeners of a single type:

function(eventType){
    getEventListeners(window).[eventType].forEach(
        function(e){
            window.removeEventListener(eventType, e.listener)
        }
    );
}

I hope this helps someone as previous answer were using the "remove" method which since then does not work anymore.

Solution 14 - Javascript

One method is to add a new event listener that calls e.stopImmediatePropagation().

Solution 15 - Javascript

var div = getElementsByTagName('div')[0]; /* first div found; you can use getElementById for more specific element */
div.onclick = null; // OR:
div.onclick = function(){};

//edit

I didn't knew what method are you using for attaching events. For addEventListener you can use this:

div.removeEventListener('click',functionName,false); // functionName is the name of your callback function

more details

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionFlorian M&#252;llerView Question on Stackoverflow
Solution 1 - JavascriptFelix KlingView Answer on Stackoverflow
Solution 2 - JavascriptpabombsView Answer on Stackoverflow
Solution 3 - JavascriptJuanGGView Answer on Stackoverflow
Solution 4 - JavascriptJmakucView Answer on Stackoverflow
Solution 5 - JavascriptJohn HenckelView Answer on Stackoverflow
Solution 6 - Javascripthossein sedighianView Answer on Stackoverflow
Solution 7 - JavascriptbaptxView Answer on Stackoverflow
Solution 8 - JavascriptJan TuroňView Answer on Stackoverflow
Solution 9 - JavascriptDorianView Answer on Stackoverflow
Solution 10 - JavascriptfeyzullahyildizView Answer on Stackoverflow
Solution 11 - JavascriptAbhilash NarayanView Answer on Stackoverflow
Solution 12 - JavascriptMicView Answer on Stackoverflow
Solution 13 - JavascriptFilipe MeloView Answer on Stackoverflow
Solution 14 - JavascriptLachoTomovView Answer on Stackoverflow
Solution 15 - JavascriptIonuț StaicuView Answer on Stackoverflow