Javascript/DOM: How to remove all event listeners of a DOM object?
Solution 1:
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. CallingremoveEventListener
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:
-
Don't use a function that returns a function. Use the function directly:
function handler() { dosomething(); } div.addEventListener('click',handler,false);
-
Create a wrapper for
addEventListener
that stores a reference to the returned function and create some weirdremoveAllEvents
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:
This will remove all listeners from children but will be slow for large pages. Brutally simple to write.
element.outerHTML = element.outerHTML;
Solution 3:
Use the event listener's own function remove()
. For example:
getEventListeners().click.forEach((e)=>{e.remove()})
Solution 4:
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:
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.