How do I remove a "listener" that I added via addeventlistener?

Asked

Viewed 643 times

8

I always use the function addEventListener to "listen" to some events, such as click, Websocket connection and the like.

For example:

var ws = new WebSocket('ws://echo.websocket.org/');

ws.addEventListener('open', function () {
       // Minha lógica
});

if (window.alguma_condicao) {
    ws.addEventListener('open', function () {
         // Minha lógica
    });
}

In the above case, in a certain situation, how could I do to remove all the "listeners" (the callbacks, which are the anonymous functions) that I added through addEventListener?

3 answers

9


It is only possible to remove a Listener using the reference to the function. That is, you cannot remove events that are created with anonymous functions.

To remove the listeners using the references, just use the function removeEventListener.

In this case, keep an eye on the parameter useCapture (the third). If the addEventListener use this parameter as true, the removeEventListener need to do the same, otherwise the event will not be removed.

Illustrative example:

const bt = document.getElementById('bt');

bt.addEventListener('click', fnClick);

function fnClick() {
  console.log('Essa é a última vez que você fez isso');
  bt.removeEventListener('click', fnClick);
}
<button id="bt">Clique aqui</button>

Another option is to remove the event within the function that adds it. This is possible by defining a named function and using the name of this function to remove the Listener or using arguments.callee.

const bt = document.getElementById('bt');
const bt2 = document.getElementById('bt2');

bt.addEventListener('click', function fn() {
  console.log('Essa é a última vez que você fez isso');
  bt.removeEventListener('click', fn);
});

bt2.addEventListener('click', function() {
  console.log('Essa é a última vez que você fez isso (2)');
  bt2.removeEventListener('click', arguments.callee);
});
<button id="bt">Clique aqui</button>
<button id="bt2">Clique aqui</button>

  • 2

    I could barely see his movements.

  • @Tobiasmesquita Just now I saw your answer XD

  • you sent your reply 5 seconds before ;D

7

Unfortunately, Javascript does not provide a way to list all events, so you will need to keep a reference to events added.

Below is an example of how to remove a specific event.

let teste = document.getElementById("teste");
let event1 = function () {
  console.log("evento 1");
}

let event2 = function () {
  console.log("evento 2");
}

let event3 = function () {
  console.log("evento 3");
}

teste.addEventListener("click", event1);
teste.addEventListener("click", event2);
teste.addEventListener("click", event3);

teste.removeEventListener("click", event2);
<button id="teste">Click Me</button>

you can implement your own Events manager.:

let EventHandler = (function () {
  let EventHandler = function (objeto) {
    this.objeto = objeto;  
    this.types = {};
  };
  EventHandler.prototype.addEvent = function (type, listener) {
    if (!this.types[type])
      this.types[type] = [];
    this.types[type].push(listener);
    this.objeto.addEventListener(type, listener);
  };
  EventHandler.prototype.removeEvent = function (type, listener) {
    if (!this.types[type])
      return;
      
    var index = this.types[type].indexOf(listener);
    this.types[type].splice(index);
    this.objeto.removeEventListener(type, listener);
  };
  EventHandler.prototype.removeAllEvent = function (type) {
    if (!this.types[type])
      return;
    this.types[type].forEach(function (listener, indice) {
      this.objeto.removeEventListener(type, listener);
    }.bind(this));
    this.types[type].length = 0;
  }
  return EventHandler;
})();

let teste = document.getElementById("teste");
let handler = new EventHandler(teste);

handler.addEvent("click", function () { console.log('event 1'); });
handler.addEvent("click", function () { console.log('event 2'); });
handler.addEvent("click", function () { console.log('event 3'); });

teste.addEventListener("click", function () {
  handler.removeAllEvent("click");
  console.log('button clicado');
});
<button id="teste">Click Me</button>

6

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 listenersstore 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);

Browser other questions tagged

You are not signed in. Login or sign up in order to post.