Remove All Event Listeners of Specific Type
Solution 1:
That is not possible without intercepting addEventListener
calls and keep track of the listeners or use a library that allows such features unfortunately. It would have been if the listeners collection was accessible but the feature wasn't implemented.
The closest thing you can do is to remove all listeners by cloning the element, which will not clone the listeners collection.
Note: This will also remove listeners on element's children.
var el = document.getElementById('el-id'),
elClone = el.cloneNode(true);
el.parentNode.replaceChild(elClone, el);
Solution 2:
If your only goal by removing the listeners is to stop them from running, you can add an event listener to the window capturing and canceling all events of the given type:
window.addEventListener(type, function(event) {
event.stopImmediatePropagation();
}, true);
Passing in true
for the third parameter causes the event to be captured on the way down. Stopping propagation means that the event never reaches the listeners that are listening for it.
Keep in mind though that this has very limited use as you can't add new listeners for the given type (they will all be blocked). There are ways to get around this somewhat, e.g., by firing a new kind of event that only your listeners would know to listen for. Here is how you can do that:
window.addEventListener('click', function (event) {
// (note: not cross-browser)
var event2 = new CustomEvent('click2', {detail: {original: event}});
event.target.dispatchEvent(event2);
event.stopPropagation();
}, true);
element.addEventListener('click2', function(event) {
if (event.detail && event.detail.original) {
event = event.detail.original
}
// Do something with event
});
However, note that this may not work as well for fast events like mousemove, given that the re-dispatching of the event introduces a delay.
Better would be to just keep track of the listeners added in the first place, as outlined in Martin Wantke's answer, if you need to do this.
Solution 3:
You must override EventTarget.prototype.addEventListener to build an trap function for logging all 'add listener' calls. Something like this:
var _listeners = [];
EventTarget.prototype.addEventListenerBase = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(type, listener)
{
_listeners.push({target: this, type: type, listener: listener});
this.addEventListenerBase(type, listener);
};
Then you can build an EventTarget.prototype.removeEventListeners:
EventTarget.prototype.removeEventListeners = function(targetType)
{
for(var index = 0; index != _listeners.length; index++)
{
var item = _listeners[index];
var target = item.target;
var type = item.type;
var listener = item.listener;
if(target == this && type == targetType)
{
this.removeEventListener(type, listener);
}
}
}
In ES6 you can use a Symbol, to hide the original function and the list of all added listener directly in the instantiated object self.
(function()
{
let target = EventTarget.prototype;
let functionName = 'addEventListener';
let func = target[functionName];
let symbolHidden = Symbol('hidden');
function hidden(instance)
{
if(instance[symbolHidden] === undefined)
{
let area = {};
instance[symbolHidden] = area;
return area;
}
return instance[symbolHidden];
}
function listenersFrom(instance)
{
let area = hidden(instance);
if(!area.listeners) { area.listeners = []; }
return area.listeners;
}
target[functionName] = function(type, listener)
{
let listeners = listenersFrom(this);
listeners.push({ type, listener });
func.apply(this, [type, listener]);
};
target['removeEventListeners'] = function(targetType)
{
let self = this;
let listeners = listenersFrom(this);
let removed = [];
listeners.forEach(item =>
{
let type = item.type;
let listener = item.listener;
if(type == targetType)
{
self.removeEventListener(type, listener);
}
});
};
})();
You can test this code with this little snipper:
document.addEventListener("DOMContentLoaded", event => { console.log('event 1'); });
document.addEventListener("DOMContentLoaded", event => { console.log('event 2'); });
document.addEventListener("click", event => { console.log('click event'); });
document.dispatchEvent(new Event('DOMContentLoaded'));
document.removeEventListeners('DOMContentLoaded');
document.dispatchEvent(new Event('DOMContentLoaded'));
// click event still works, just do a click in the browser
Solution 4:
Remove all listeners on a global event
element.onmousedown = null;
now you can go back to adding event listeners via
element.addEventListener('mousedown', handler, ...);
This solution only works on "Global" events. Custom events won't work. Here's a list of all global events: https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers