A not very trivial way to perform the task is intercept function call addEventListener
and keep the reference to the function in some way, because, as stated in the other responses, it would not be possible to remove an anonymous function (or Arrow Function) since we would not have the reference of this one. If we store the reference, the solution becomes possible.
Considering that such a solution might be necessary in a production application, it would not be interesting to have to modify the entire code, such as naming all anonymous functions or calling our custom function instead of addEventListener
. The most practical thing would be if we defined such behavior as a function standard addEventListener
and it is possible to reimplementate it through Element.prototype.addEventListener
. However, as we will need the original function, we need to create a backup of a different name:
Element.prototype._AddEventListener = Element.prototype.addEventListener;
Here, the function addEventListener
original becomes _addEventListener
.
To then define our function addEventListener
customized:
Element.prototype.addEventListener = function(type, listener, useCapture = false) {
if (typeof this.listeners === "undefined") {
this.listeners = [];
}
this.listeners.push({type: type, listener: listener, useCapture: useCapture});
this._AddEventListener(type, listener, useCapture);
};
That is, when the function is called, it will be checked whether the element has an attribute listeners
store all references to listeners added. If it does not have it, it is defined as an empty list and then added the Listener to the list, also storing the event name and the value of useCapture
. At the end, the function is called _addEventListener
, which is the original function, so the original behavior of the function remains unchanged.
Now, to remove all listeners of an element, we can define a new function:
EventTarget.prototype.removeEventListeners = function(type = null, useCapture = false) {
if (typeof this.listeners !== "undefined") {
for (let i = 0; i < this.listeners.length; i++) {
if ((type == this.listeners[i].type || type === null) && useCapture == this._listeners[i].useCapture) {
this.removeEventListener(type, this.listeners[i].listener, useCapture);
}
}
}
};
Understand the s
in removeEventListeners
not to conflict with the original function. Basically the function checks if the element has a list of listeners and, if it possesses, goes through removing all the listeners match the function parameters. That is, if set the value of type
, will be removed all listeners associated with the event defined by type
whose the vajor of useCapture
is the same as the one passed by parameter. If called without parameters, all listeners of all events with useCapture
phony.
Let’s see in practice:
// Mantemos a função original de addEventListener:
EventTarget.prototype.originalAddEventListener = EventTarget.prototype.addEventListener;
// Definimos uma função nova que armazena a referência dos listeners:
EventTarget.prototype.addEventListener = function(type, listener, useCapture = false) {
if (typeof this._listeners === "undefined") {
this._listeners = [];
}
this._listeners.push({type: type, listener: listener, useCapture: useCapture});
this.originalAddEventListener(type, listener, useCapture);
};
EventTarget.prototype.removeEventListeners = function(type = null, useCapture = false) {
if (typeof this._listeners !== "undefined") {
for (let i = 0; i < this._listeners.length; i++) {
if ((type == this._listeners[i].type || type === null) && useCapture == this._listeners[i].useCapture) {
this.removeEventListener(type, this._listeners[i].listener, useCapture);
}
}
}
};
// Link 1, quando pressionado, muda a cor da fonte para vermelho.
document.getElementById("a1").addEventListener("click", function (event) {
this.style.color = "red";
});
// Link 2, quando pressionado, muda a cor da fonte para azul, mas o evento é removido.
document.getElementById("a2").addEventListener("click", function (event) {
this.style.color = "blue";
});
document.getElementById("a2").removeEventListeners("click");
// Link 3, quando pressionado, muda a cor da fonte para verde. O evento é definido como useCapture=true, mas é tentado remover com useCapture=false.
document.getElementById("a3").addEventListener("click", function (event) {
this.style.color = "green";
}, true);
document.getElementById("a3").removeEventListeners("click");
<a href="#!" id="a1">Link 1</a>
<a href="#!" id="a2">Link 2</a>
<a href="#!" id="a3">Link 3</a>
- The
Link 1
keeps the event as added;
- The
Link 2
returns to original behavior, as the Listener is removed;
- The
Link 3
maintains the event as it is added with useCapture=true
and tried to remove with useCapture=false
.
In this way, it is possible to remove listeners even if they are defined as an anonymous function or an Arrow Function.
Summary of calls from removeEventListeners
:
// Remove os listeners do evento `click`, com useCapture=False:
element.removeEventListeners("click");
// Remove os listeners do evento `click`, com useCapture=True:
element.removeEventListeners("click", true);
// Remove todos os listeners, com useCapture=False:
element.removeEventListeners();
// Remove todos os listeners, com useCapture=True:
element.removeEventListeners(null, true);
I could barely see his movements.
– Tobias Mesquita
@Tobiasmesquita Just now I saw your answer XD
– Jéf Bueno
you sent your reply 5 seconds before ;D
– Tobias Mesquita