vincular evento solo una vez

104

Tengo el siguiente código:

function someMethod()
{
  $(obj).click(function {});
}

someMethod se llama dos veces y, por lo tanto, el evento de clic se enlaza dos veces. ¿Cómo puedo hacer que se una solo una vez?

pájaro de fuego
fuente
posible duplicado del modelo de eventos
Cees Timmerman

Respuestas:

190

Si puede aplicarlo, probablemente quiera echar un vistazo a event.preventDefault y event.stopPropagation O desvincular y vincular cada vez, dentro de su método como

function someMethod()
{
  $(obj).off('click').on('click', function(e) {
    // put your logic in here 
  });
}
pna
fuente
19
Tenga cuidado, porque esto desvincula TODOS los eventos de clic y no siempre es un comportamiento deseado. Por ejemplo, cuando vincula algo a un documento, solo desea desvincular ese evento, no todos.
Mārtiņš Briedis
26
En caso de que no desee desvincular accidentalmente otros eventos de clic, es posible que desee utilizar function someMethod() { $(obj).off('click.namespace').on('click.namespace', function {}); }
Manu
@Manu copió de esta respuesta
aexl
89

Además de la respuesta de pna, es posible que desee pensar en el espacio de nombres de su evento para no anular la vinculación accidental de todos los eventos de clic.

function someMethod () {
    $ (obj) .unbind ('click.namespace'). bind ('click.namespace', function () {});
}

https://api.jquery.com/event.namespace/

Iain
fuente
10
Esta debería ser la respuesta aceptada. Desvincular todos los eventos de clic puede romper las cosas fácilmente, especialmente si es un proyecto complejo con una gran cantidad de jQuery. ¡Gracias por eso! ¡No sabía nada de esta sencilla solución de espacio de nombres!
Simon Steinberger
Con el jQuery actual, esto debería ser $(obj).off()y $(obj).on()respectivamente. De lo contrario, el espacio de nombres ayudó y funcionó. ¡Gracias!
aexl
19

No hay un método integrado para determinar si ya ha vinculado esta función en particular. Puede vincular varias funciones de clic a un objeto. Por ejemplo:

$('#id').bind('click', function(){
alert('hello');
});


$('#id').bind('click', function(){
alert('goodbuy');
});

Si hace lo anterior cuando se hace clic en el objeto, le avisará hola y luego adiós. Para asegurarse de que solo una función esté vinculada al evento de clic, desvincule el controlador de eventos de clic y luego vincule la función deseada de esta manera:

$(obj).unbind('click').bind('click', function(){... });
Matt Paxton
fuente
12

La solución obvia es no llamar someMethod()dos veces. Si no puede solucionarlo, puede mantener una variable de estado para que solo se una una vez de esta manera:

function someMethod()
{
    if (!someMethod.bound) {
        $(obj).click(function() {});
        someMethod.bound = true;
    }
}

Nota: esto usa una propiedad de la función en sí en lugar de introducir una variable global para realizar un seguimiento de si se ha vinculado. También puede utilizar una propiedad en el propio objeto.

Puedes verlo funcionar aquí: http://jsfiddle.net/jfriend00/VHkxu/ .

jfriend00
fuente
11

O use la función one () de jQuery que es similar a on () pero solo activa el evento una vez, incluso si lo vincula varias veces.

http://api.jquery.com/one/

xandrw
fuente
8
A veces ayuda. pero a veces quieres una solución en la que puedas: ADJUNTAR UNA VEZ PERO UTILIZAR MUCHAS.
Rzassar
5

jQuery hace que llamar a alguna función sea posible solo una vez bastante fácil:

function someMethod()
{

     $(obj).click(function() {});
      this.someMethod = $.noop;
}
Esailija
fuente
1
Esto solo funcionará si someMethod es un método de un objeto o función global.
jcubic
jQuery.noopes solo un carácter más corto que function(){}, por lo que es un poco tonto decir que "ayuda" aquí, solo que proporciona una función vacía. Aquí hay un ejemplo sin método de jQuery de esta solución general:var fn = function(){ fn = function(){}; do stuff; };
1j01
1
@ 1j01 Editado para usar $en su lugar
Esailija
2

Esta es una sugerencia ya que no conozco su lógica. Puede o no funcionar para usted.

Intente combinar las funciones jquery live () y one () le dará un mejor resultado que las revinculaciones de eventos.

Los casos especiales funcionan cuando tienes 2 elementos DOM (padre e hijo). Live () en el nodo principal se asegura de que se invoque el evento y luego llama a one () para registrar dinámicamente el evento que se ejecutará solo una vez. (esto proporciona una funcionalidad similar a la de volver a enlazar).

Bambú
fuente
One()la función funcionó chromepero no funcionó safarien Mac.
Príncipe mestizo
2

Puede agregar la clase css a los elementos enlazados y luego filtrarlos:

function someMethod()
{
    $(obj).not('.click-binded')
          .click(function {})
          .addClass('click-binded');
}

Este método también se puede utilizar para complementos:

  $(obj).not('.datetimepicker-applied')
        .datetimepicker()
        .addClass('datetimepicker-applied');
Bakyt Abdrasulov
fuente
1
var bound = false;

function someMethod()
{
    if(!bound)
    {
       $(obj).click(function {});
       bound = true;
    }
}

pero probablemente investigaría por qué se llama dos veces antes de hacer algún tipo de solución.

Kai Qing
fuente
3
Si va de esta manera, considere la solución de jfriend00 donde boundse adjunta en someMethod()lugar de contaminar el espacio de nombres global.
nuala
1

Si desea vincularse al objeto solo una vez, debe implementar una bandera y ceñirse a ese objeto.

Por ejemplo:

if($('#id') && $('#id').data('done') == null)) {
    $('#id').bind('click', function() {
        alert('hello');
    });

    $('#id').data('done', true);
}
cscan
fuente
1

Puede utilizar esta función de extensión jQuery.

$.fn.once = function (type, fn, uid) {
  if(uid == undefined) {
    console.error("Called $.once without uid\n", this, "\n", fn);
  }

  var dataStr = type+"-handler-"+uid;
  if(!this.data(dataStr)) {
    this.data(dataStr, true);
    this.on(type, fn);
  }
};

En lugar de hacer esto

$("button").on("click", function(){
  alert("You Clicked On A Button");
});

Ya haces esto

$("button").once("click", function(){
  alert("You Clicked On A Button");
}, "btnHandler");

Ahora, cuando tengo una función a su alrededor

function addBtnHandler() {
  $("button").once("click", function() {
    alert("You Clicked On A Button");
  }, "btnHandler");
}

Y lo llamo varias veces

addBtnHandler();
addBtnHandler();
addBtnHandler();

Solo lo hace una vez.

Observe que la extensión funciona verificando tanto uid como type. Esto significa que puede vincular diferentes tipos de controladores con el mismo uid, puede que desee o no. Para cambiarlo editar.

var dataStr = type+"-handler-"+uid;

Con algo como

var dataStr = "handler-"+uid;

Nathnolt
fuente
1

También estaba tratando de usar el método de activación y desactivación de jquery para vincular el evento solo una vez con el elemento dom que aún no existe o el elemento dom aún no se ha creado.

$('.select').off('event').on('event', 'selector', function(e){ // });

Este código no funcionaba correctamente

Me encontré con un método muy lucrativo que es 'un' método. Es muy útil cuando desea vincular un evento solo una vez.

Puedes encontrar el documento aquí http://api.jquery.com/one/

Esto es lo mismo que el método 'on' pero diferente en su comportamiento con no quedarse con el evento para múltiples selectores.

$('body').one('click', 'selector', function(){ // do your stuff here });
Ankit Vishwakarma
fuente
1

Puede lograr esto con JS puro, usando el método addEventListener y su opción once

target.addEventListener('click', handler, {once: true});
Skav
fuente
2
Esto hace que el evento se desate después de hacer clic una vez en el elemento. Esto no resuelve el problema de que los eventos estén vinculados varias veces.
Top Cat