événement lié une seule fois

Réponses:

190

Si vous pouvez l'appliquer, vous voudrez probablement jeter un coup d'œil à event.preventDefault et event.stopPropagation OU dissocier et lier à chaque fois, dans votre méthode comme

function someMethod()
{
  $(obj).off('click').on('click', function(e) {
    // put your logic in here 
  });
}
pna
la source
19
Soyez prudent, car cela dissocie TOUS les événements de clic et ce n'est pas toujours un comportement souhaité. Par exemple, lorsque vous liez quelque chose à un document, vous souhaitez dissocier uniquement cet événement, pas tous.
Mārtiņš Briedis
26
Si vous ne souhaitez pas dissocier accidentellement d'autres événements de clic, vous pouvez utiliser function someMethod() { $(obj).off('click.namespace').on('click.namespace', function {}); }
Manu
@Manu vous avez copié à partir de cette réponse
aexl
89

En plus de la réponse de pna, vous voudrez peut-être penser à l'espace de noms de votre événement afin de ne pas détacher accidentellement tous les événements de clic.

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

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

Iain
la source
10
Cela devrait être la réponse acceptée. La suppression de la liaison de tous les événements de clic peut facilement casser les choses, surtout s'il s'agit d'un projet complexe avec beaucoup de jQuery en cours. Merci pour ça! Je ne connaissais pas cette solution d'espace de noms simple !!
Simon Steinberger
Avec le jQuery actuel, cela devrait être $(obj).off()et $(obj).on()respectivement. Sinon, l'espacement des noms a aidé et cela a fonctionné. Je vous remercie!
aexl
19

Il n'y a pas de méthode intégrée pour déterminer si vous avez déjà lié cette fonction particulière. Vous pouvez lier plusieurs fonctions de clic à un objet. Par exemple:

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


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

si vous faites ce qui précède lorsque vous cliquez sur l'objet, il alertera bonjour puis au revoir. Pour vous assurer qu'une seule fonction est liée à l'événement click, dissociez le gestionnaire d'événements click puis liez la fonction souhaitée comme ceci:

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

La solution évidente est de ne pas appeler someMethod()deux fois. Si vous ne pouvez pas résoudre ce problème, vous pouvez conserver une variable d'état afin qu'elle ne se lie qu'une seule fois comme ceci:

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

Remarque: cela utilise une propriété de la fonction elle-même plutôt que d'introduire une variable globale pour savoir si elle a été liée. Vous pouvez également utiliser une propriété sur l'objet lui-même.

Vous pouvez le voir fonctionner ici: http://jsfiddle.net/jfriend00/VHkxu/ .

jfriend00
la source
11

Ou utilisez la fonction one () de jQuery qui est similaire à on () mais ne déclenche l'événement qu'une seule fois, même si vous le liez plusieurs fois.

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

xandrw
la source
8
Parfois ça aide. mais parfois vous voulez la solution dans laquelle vous pouvez: ATTACHER UNE FOIS MAIS UTILISEZ BEAUCOUP.
Rzassar
5

jQuery permet d'appeler une fonction une seule fois assez facilement:

function someMethod()
{

     $(obj).click(function() {});
      this.someMethod = $.noop;
}
Esailija
la source
1
Cela ne fonctionnera que si someMethod est la méthode d'un objet ou d'une fonction globale.
jcubic
jQuery.noopest seulement un caractère plus court que function(){}, donc c'est un peu ridicule de dire que c'est "aider" ici, en fournissant juste une fonction vide. Voici un exemple non-jQuery non-méthode de cette solution générale:var fn = function(){ fn = function(){}; do stuff; };
1j01
1
@ 1j01 Modifié pour être utilisé à la $place
Esailija
2

Ceci est une suggestion car je ne connais pas votre logique. Peut ou peut ne pas fonctionner pour vous.

Essayez de combiner les fonctions jquery live () et one () pour obtenir un meilleur résultat que les rebinds d'événements.

Les cas spéciaux fonctionnent lorsque vous avez 2 éléments DOM (parent et enfant). Live () au nœud parent s'assure que l'événement sera invoqué, puis appelle one () pour enregistrer dynamiquement l'événement qui ne serait exécuté qu'une seule fois. (cela fournit des fonctionnalités similaires comme les rebinds).

Bambou
la source
One()fonction a travaillé dans chromemais ne fonctionnait pas safaridans Mac.
Half Blood Prince
2

Vous pouvez ajouter une classe css aux éléments liés, puis les filtrer:

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

Cette méthode peut également être utilisée pour les plugins:

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

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

mais je chercherais probablement pourquoi il est appelé deux fois avant de faire une sorte de contournement.

Kai Qing
la source
3
Si vous allez de cette façon, considérez la solution de jfriend00 où boundest attaché au someMethod()lieu de polluer l'espace de nom global.
nuala le
1

Si vous ne souhaitez vous lier à l'objet qu'une seule fois, vous devez implémenter un indicateur et vous en tenir à cet objet.

Par exemple:

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

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

Vous pouvez utiliser cette fonction d'extension 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);
  }
};

Au lieu de faire ça

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

Tu fais ça

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

Maintenant, quand j'ai une fonction autour d'elle

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

Et je l'appelle plusieurs fois

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

Il ne le fait qu'une seule fois.

Notez que l'extension fonctionne en vérifiant à la fois l'uid et le type. Cela signifie que vous pouvez lier différents types de gestionnaires avec le même uid, vous pouvez ou non le vouloir. Pour le changer, éditez.

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

Avec quelque chose comme

var dataStr = "handler-"+uid;

Nathnolt
la source
1

J'essayais également d'utiliser la méthode off and on de jquery pour lier un événement une seule fois avec l'élément dom qui n'existe pas encore ou l'élément dom n'est pas encore créé.

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

Ce code ne fonctionnait pas correctement

Je suis tombé sur une méthode très lucrative qui est «une» méthode. C'est très utile lorsque vous souhaitez lier un événement une seule fois.

Vous pouvez trouver le document ici http://api.jquery.com/one/

C'est la même chose que la méthode 'on' mais différente avec son comportement avec ne pas s'en tenir à l'événement pour plusieurs sélecteurs.

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

Vous pouvez y parvenir avec pur JS, en utilisant la méthode addEventListener et son option once

target.addEventListener('click', handler, {once: true});
Skav
la source
2
Cela entraîne la dissociation de l'événement après un clic sur l'élément. Cela ne résout pas le problème des événements liés plusieurs fois.
Top Cat