¿Cómo puedo eliminar un detector de eventos de JavaScript?

5 minutos de lectura

avatar de usuario de thomas
tomas

Estoy tratando de eliminar un detector de eventos dentro de una definición de detector:

canvas.addEventListener('click', function(event) {
    click++;
    if(click == 50) {
        // remove this event listener here!
    }
// More code here ...

¿Cómo podría hacer eso? esto = evento…

  • trivial pero para futuras referencias if(click == 50) { debiera ser if( click === 50 ) o if( click >= 50 ) – no cambiarán la salida, pero por razones de cordura estas comprobaciones tienen más sentido.

    – rimon

    14/03/2012 a las 21:22

  • Buena pregunta… ¿cómo lo elimino si no tengo acceso al contenido? Quiero eliminar las ventanas emergentes para hacer clic en los botones usando GreaseMonkey para otros sitios, pero a menos que pueda hacer referencia a la función por su nombre, no parece que encuentre la forma de eliminarla.

    – JasonXA

    26 de junio de 2015 a las 19:12

avatar de usuario de user113716
usuario113716

Necesitas usar funciones con nombre.

También el click la variable debe estar fuera del controlador para incrementar.

var click_count = 0;

function myClick(event) {
    click_count++;
    if(click_count == 50) {
       // to remove
       canvas.removeEventListener('click', myClick);
    }
}

// to add
canvas.addEventListener('click', myClick);

Podrías cerrar alrededor de la click_counter variables como esta:

var myClick = (function( click_count ) {
    var handler = function(event) {
        click_count++;
        if(click_count == 50) {
           // to remove
           canvas.removeEventListener('click', handler);
        }
    };
    return handler;
})( 0 );

// to add
canvas.addEventListener('click', myClick);

De esta manera, puede incrementar el contador en varios elementos.


Si no quieres eso y quieres que cada uno tenga su propio contador, entonces haz esto:

var myClick = function( click_count ) {
    var handler = function(event) {
        click_count++;
        if(click_count == 50) {
           // to remove
           canvas.removeEventListener('click', handler);
        }
    };
    return handler;
};

// to add
canvas.addEventListener('click', myClick( 0 ));

  • Voto a favor, la tercera opción aquí es una parte importante para comprender el enlace/desenlace de JS

    – SW4

    19 mayo 2015 a las 14:18


  • haría myClick = function(event){...} ser considerada una función nombrada también?

    – Daniel Möller

    28 de julio de 2015 a las 18:35

  • Me pregunto si podría hacer: myClick = function....entonces another = myClick y finalmente removeEventListener('click', another) ??

    – Daniel Möller

    28 de julio de 2015 a las 19:02

  • @Daniel desde myClick(0) devuelve una función, por supuesto que puedes

    – alebianco

    20 de diciembre de 2016 a las 9:15

  • Tenga en cuenta que, si bien era cierto en 2010, esto no ha sido así desde finales de 2020, cuando se introdujeron las señales de control para los eventos. Tú no más necesitan funciones con nombre, o incluso removeEventListener para el caso: puede abortar un evento directamente en estos días.

    -Mike ‘Pomax’ Kamermans

    27 de julio de 2022 a las 15:33


   canvas.addEventListener('click', function(event) {
      click++;
      if(click == 50) {
          this.removeEventListener('click',arguments.callee,false);
      }

Deberías hacerlo.

  • ¡Esto es genial! documento en arguments.callee para los interesados: desarrollador.mozilla.org/en/JavaScript/Reference/…

    – Ender

    9 de diciembre de 2010 a las 19:48

  • Desafortunadamente, esto no funciona con ECMAScript 5 (2009) o posterior, desde el enlace de MDN: “La 5.ª edición de ECMAScript (ES5) prohíbe el uso de arguments.callee() en modo estricto. Evitar el uso de arguments.callee() ya sea dando un nombre a las expresiones de función o usando una declaración de función donde una función debe llamarse a sí misma.” (aunque está usando callee() en lugar de calleetodavía está eliminado, ¡boo!)

    – Dai

    30 de mayo de 2020 a las 2:18

Avatar de usuario de Tama
tama

Puede usar una expresión de función con nombre (en este caso, la función se llama abc), al igual que:

let click = 0;
canvas.addEventListener('click', function abc(event) {
    click++;
    if (click >= 50) {
        // remove event listener function `abc`
        canvas.removeEventListener('click', abc);
    }
    // More code here ...
}

Ejemplo de trabajo rápido y sucio: http://jsfiddle.net/8qvdmLz5/2/.

Más información sobre las expresiones de funciones con nombre: http://kangax.github.io/nfe/.

Avatar de usuario de Brad Christie
brad christie

Si la solución de @Cybernate no funciona, intente dividir el gatillo en su propia función para que pueda hacer referencia a ella.

clickHandler = function(event){
  if (click++ == 49)
    canvas.removeEventListener('click',clickHandler);
}
canvas.addEventListener('click',clickHandler);

element.querySelector('.addDoor').onEvent('click', function (e) { });
element.querySelector('.addDoor').removeListeners();


HTMLElement.prototype.onEvent = function (eventType, callBack, useCapture) {
this.addEventListener(eventType, callBack, useCapture);
if (!this.myListeners) {
    this.myListeners = [];
};
this.myListeners.push({ eType: eventType, callBack: callBack });
return this;
};


HTMLElement.prototype.removeListeners = function () {
if (this.myListeners) {
    for (var i = 0; i < this.myListeners.length; i++) {
        this.removeEventListener(this.myListeners[i].eType, this.myListeners[i].callBack);
    };
   delete this.myListeners;
};
};

Parece que nadie ha cubierto la parte de la especificación DOM de JavaScript actual que le brinda un mecanismo para eliminar su detector de eventos sin usando removeEventListener. si miramos https://dom.spec.whatwg.org/#concept-event-listener vemos que hay una serie de propiedades que se pueden pasar para controlar la escucha de eventos:

{
  type (a string)
  callback (null or an EventListener object)
  capture (a boolean, initially false)
  passive (a boolean, initially false)
  once (a boolean, initially false)
  signal (null or an AbortSignal object)
  removed (a boolean for bookkeeping purposes, initially false) 
}

Ahora, hay muchas propiedades útiles en esa lista, pero para eliminar un detector de eventos, es el signal propiedad que queremos usar (que se agregó al DOM nivel 3 a finales de 2020), porque nos permite decirle al motor JS que elimine un detector de eventos simplemente llamando abort() en lugar de tener que molestarse con removeEventListener:

const canvasListener = (new AbortController()).signal;

canvas.addEventListener('click', () => {
  click++;
  if (click === 50) {
    canvasListener.abort();
  } else {
    doSomethingWith(click);
  }
}, {
  signal: canvasListener 
});

(Tenga en cuenta que esto no utiliza el useCapture bandera, porque la bandera useCapture es esencialmente completamente inútil)

Y listo: el motor JS abortará y limpiará nuestro detector de eventos. Sin mantener una referencia a la función de manejo, sin asegurarse de que llamemos removeEventListener con exactamente las mismas propiedades que llamamos addEventListener: simplemente cancelamos el oyente.

Creo que es posible que deba definir la función del controlador con anticipación, así:

var myHandler = function(event) {
    click++; 
    if(click == 50) { 
        this.removeEventListener('click', myHandler);
    } 
}
canvas.addEventListener('click', myHandler);

Esto le permitirá eliminar el controlador por su nombre desde dentro de sí mismo.

¿Ha sido útil esta solución?