Remove All Event Listeners of Specific Type

Remove All Event Listeners of Specific Type

I want to remove all event listeners of a specific type that were added using addEventListener(). All the resources I’m seeing are saying you need to do this:
elem.addEventListener(‘mousedown’,specific_function);
elem.removeEventListener(‘mousedown’,specific_function);

But I want to be able to clear it without knowing what it is currently, like this:
elem.addEventListener(‘mousedown’,specific_function);
elem.removeEventListener(‘mousedown’);

Solutions/Answers:

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.stopPropagation();
}, 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.

Solution 3:

I know this is old, but I had a similar issue with no real answers, where I wanted to remove all “keydown” event listeners from the document. Instead of removing them, I overrode the addEventListener to ignore them before they were even added, similar to Toms answer above, by adding this before any other scripts are loaded.:

<script type="text/javascript">
    var current = document.addEventListener;
    document.addEventListener = function (type, listener) {
        if(type =="keydown")
        {
            //do nothing
        }
        else
        {
            var args = [];
            args[0] = type;
            args[1] = listener;
            current.apply(this, args);
        }
    };
</script>

Solution 4:

You could alternatively overwrite the ‘yourElement.addEventListener()’ method and use the ‘.apply()’ method to execute the listener like normal, but intercepting the function in the process. Like:

<script type="text/javascript">

    var args = [];
    var orginalAddEvent = yourElement.addEventListener;

    yourElement.addEventListener = function() {
        //console.log(arguments);
        args[args.length] = arguments[0];
        args[args.length] = arguments[1];
        orginalAddEvent.apply(this, arguments);
    };

    function removeListeners() {
        for(var n=0;n<args.length;n+=2) {
            yourElement.removeEventListener(args[n], args[n+1]);
        }
    }

    removeListeners();

</script>

This script must be run on page load or it might not intercept all event listeners.

Make sure to remove the ‘removeListeners()’ call before using.

Solution 5:

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 6:

In the extreme case of not knowing which callback is attached to a window listener, an handler can be wrapper around window addEventListener and a variable can store ever listeners to properly remove each one of those through a removeAllEventListener('scroll') for example.

var listeners = {};

var originalEventListener = window.addEventListener;
window.addEventListener = function(type, fn, options) {
    if (!listeners[type])
        listeners[type] = [];

    listeners[type].push(fn);
    return originalEventListener(type, fn, options);
}

var removeAllEventListener = function(type) {
    if (!listeners[type] || !listeners[type].length)
        return;

    for (let i = 0; i < listeners[type].length; i++)
        window.removeEventListener(type, listeners[type][i]);
}