web-dev-qa-db-fra.com

événements de clic jQuery se déclenchant plusieurs fois

J'essaie d'écrire un jeu de vidéo poker en Javascript afin d'en comprendre les bases, et j'ai rencontré un problème où les gestionnaires d'événements de clic jQuery se déclenchent plusieurs fois.

Ils sont attachés à des boutons pour placer un pari, et cela fonctionne très bien pour placer un pari sur la première main pendant un match (tirer une seule fois); mais dans les paris pour la trotteuse, l'événement de clic est déclenché deux fois à chaque fois qu'un bouton de pari ou de pari est enfoncé (le montant correct est donc doublé à chaque fois que vous appuyez). Dans l’ensemble, il suit ce modèle pendant le nombre de fois où l’événement clic est déclenché lorsqu’on appuie une fois sur un bouton de pari - où le terme ith de la séquence est pour le pari de la main ith depuis le début le jeu: 1, 2, 4, 7, 11, 16, 22, 29, 37, 46, qui semble être n (n + 1)/2 + 1 pour ce que ça vaut - et je n’étais pas assez intelligent pour comprendre cela, j'ai utilisé OEIS . :)

Voici la fonction avec les gestionnaires d’événements click qui agissent; j'espère que c'est facile à comprendre (laissez-moi savoir si ce n'est pas le cas, je veux m'améliorer aussi):

/** The following function keeps track of bet buttons that are pressed, until place button is pressed to place bet. **/
function pushingBetButtons() {
    $("#money").text("Money left: $" + player.money); // displays money player has left

    $(".bet").click(function() {
        var amount = 0; // holds the amount of money the player bet on this click
        if($(this).attr("id") == "bet1") { // the player just bet $1
            amount = 1;
        } else if($(this).attr("id") == "bet5") { // etc.
            amount = 5;
        } else if($(this).attr("id") == "bet25") {
            amount = 25;
        } else if($(this).attr("id") == "bet100") {
            amount = 100;
        } else if($(this).attr("id") == "bet500") {
            amount = 500;
        } else if($(this).attr("id") == "bet1000") {
            amount = 1000;
        }
        if(player.money >= amount) { // check whether the player has this much to bet
            player.bet += amount; // add what was just bet by clicking that button to the total bet on this hand
            player.money -= amount; // and, of course, subtract it from player's current pot
            $("#money").text("Money left: $" + player.money); // then redisplay what the player has left
        } else {
            alert("You don't have $" + amount + " to bet.");
        }
    });

    $("#place").click(function() {
        if(player.bet == 0) { // player didn't bet anything on this hand
            alert("Please place a bet first.");
        } else {
            $("#card_para").css("display", "block"); // now show the cards
            $(".card").bind("click", cardClicked); // and set up the event handler for the cards
            $("#bet_buttons_para").css("display", "none"); // hide the bet buttons and place bet button
            $("#redraw").css("display", "block"); // and reshow the button for redrawing the hand
            player.bet = 0; // reset the bet for betting on the next hand
            drawNewHand(); // draw the cards
        }
    });
}

S'il vous plaît, faites-moi savoir si vous avez des idées ou des suggestions, ou si la solution à mon problème est similaire à la solution d'un autre problème ici (j'ai examiné de nombreux threads portant le même titre et je n'ai pas eu la chance de trouver une solution qui puisse fonctionner. pour moi).

237
Gregory Fowler

Pour vous assurer qu'un clic seulement les actions une fois utilisent ceci:

$(".bet").unbind().click(function() {
    //Stuff
});
442
Rob

.unbind() est obsolète et vous devriez plutôt utiliser la méthode .off() . Appelez simplement .off() juste avant d’appeler .on().

Cela supprimera tous les gestionnaires d'événements:

$(element).off().on('click', function() {
    // function body
});

Pour supprimer uniquement les gestionnaires d'événements 'Cliquez' enregistrés:

$(element).off('click').on('click', function() {
    // function body
});
331
mtl

.un()

Une meilleure option serait .one():

Le gestionnaire est exécuté au plus une fois par élément et par type d'événement.

$(".bet").one('click',function() {
    //Your function
});

En cas de plusieurs classes et chaque classe doit être cliqué une fois,

$(".bet").on('click',function() {
    //Your function
    $(this).off('click');   //or $(this).unbind()
});
125
Shaunak D

Si vous trouvez que .off () .unbind () ou .stopPropagation () ne résout toujours pas votre problème, essayez d’utiliser .stopImmediatePropagation () Fonctionne très bien dans les situations où vous souhaitez simplement que votre événement soit géré tout bouillonnement et sans effectuer aucun autre événement déjà en cours de traitement. Quelque chose comme:

$(".bet").click(function(event) {
  event.stopImmediatePropagation();
  //Do Stuff
});

fait le tour!

65
Alfonse Pinto

Si vous appelez cette fonction à chaque "clic", il s'agit de ajout / d'une autre paire de gestionnaires à chaque appel.

Ajouter des gestionnaires avec jQuery n’est tout simplement pas comme définir la valeur de l’attribut "onclick". On peut ajouter autant de gestionnaires que l'on veut.

16
Pointy

c'est un vieux problème, mais j'y ai fait face aujourd'hui, et je pense que ma réponse aidera les futurs chercheurs de défis similaires.

il est exécuté plusieurs fois, car la fonction "on ('click', somefunction)" est appelée plusieurs fois et, par conséquent, elle est liée plusieurs fois. Pour résoudre ce problème de manière permanente, vous devez vous assurer que placez qu'il ne sera exécuté qu'une fois. après quoi, sur l'événement de clic de souris, la fonction ne sera déclenchée qu'une seule fois.

par exemple, si je mets "sur (" clic ", une fonction)" dans un endroit où il sera chargé deux fois, puis à chaque clic - "une fonction" sera déclenchée deux fois.

dans une séquence logique correcte, la fonction "off" ne doit être utilisée que lorsque vous avez vraiment l'intention de dissocier les événements. l'utiliser pour masquer les erreurs logiques dues au double chargement de la fonction "on" n'est pas une bonne approche, même si cela peut sembler fonctionner.

5
Kalpesh Popat

J'ai eu un problème à cause du balisage.

HTML:

<div class="myclass">
 <div class="inner">

  <div class="myclass">
   <a href="#">Click Me</a>
  </div>

 </div>
</div>

jQuery

$('.myclass').on('click', 'a', function(event) { ... } );

Vous remarquez que j'ai la même classe "myclass" deux fois en HTML, donc il appelle click pour chaque instance de div.

4
Bobz

Tous les trucs sur .on () et .one () sont excellents, et jquery est génial.

Mais parfois, vous voulez qu'il soit un peu plus évident que l'utilisateur ne soit pas autorisé à cliquer, et dans ces cas, vous pouvez faire quelque chose comme ceci:

function funName(){
    $("#orderButton").prop("disabled", true);
    //  do a bunch of stuff
    // and now that you're all done
    setTimeout(function(){
        $("#orderButton").prop("disabled",false);
        $("#orderButton").blur();
    }, 3000);
}

et votre bouton ressemblerait à ceci:

<button onclick='funName()'>Click here</button>
3
rikkitikkitumbo

La meilleure option serait d’utiliser off

<script>
function flash() {
  $("div").show().fadeOut("slow");
}
$("#bind").click(function() {
  $( "body" )
    .on("click", "#theone", flash)
    .find("#theone")
      .text("Can Click!");
});
$("#unbind").click(function() {
  $("body")
    .off("click", "#theone", flash)
    .find("#theone")
      .text("Does nothing...");
});
</script>
2
arc_shiva

Dans mon cas, j'utilisais «délégué», donc aucune de ces solutions ne fonctionnait. Je crois que c’est le bouton qui apparaît plusieurs fois via des appels ajax qui était à l’origine du problème des clics multiples. La solution utilisait un délai d'expiration pour que seul le dernier clic soit reconnu:

var t;
$('body').delegate( '.mybutton', 'click', function(){
    // clear the timeout
    clearTimeout(t);
    // Delay the actionable script by 500ms
    t = setTimeout( function(){
        // do something here
    },500)
})
2
Trevor Lettman
$('.bed').one(function(){ })

Docs:

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

2
Conner Gesbocker

Nous devons stopPropagation() afin d'éviter que Clicks déclenche trop souvent des événements.

$(this).find('#cameraImageView').on('click', function(evt) {
   evt.stopPropagation();
   console.log("Camera click event.");
});

Il empêche l’événement de remonter dans l’arborescence DOM, empêchant ainsi les gestionnaires parents d’être avertis de l’événement. Cette méthode n'accepte aucun argument.

Nous pouvons utiliser event.isPropagationStopped() pour déterminer si cette méthode a déjà été appelée (sur cet objet événement).

Cette méthode fonctionne également pour les événements personnalisés déclenchés avec trigger (). Notez que cela n’empêche pas les autres gestionnaires du même élément de s’exécuter.

2
Daniel Raja Singh

Cela se produit car l'événement est lié plusieurs fois au même élément.

La solution qui a fonctionné pour moi est la suivante:

Tuez tous les événements attachés en utilisant la méthode .die().

Et puis attachez votre méthode listener.

Ainsi, 

$('.arrow').click(function() {
// FUNCTION BODY HERE
}

devrait être:

$('.arrow').die("click")
$('.arrow').click(function() {
// FUNCTION BODY HERE
}
2
Pupil

Quand je traite de ce problème, j'utilise toujours:

$(".bet").unbind("click").bind("click", function (e) {
  // code goes here
}

De cette façon, je dissocie et relie du même coup.

1
Andy
$(element).click(function (e)
{
  if(e.timeStamp !== 0) // This will prevent event triggering more then once
   {
      //do your stuff
   }
}
1
Rajan Rajan M

.one ne se déclenche qu'une fois pendant la durée de vie de la page 

Donc, si vous voulez effectuer une validation, ce n'est pas la bonne solution, car si vous ne quittez pas la page après validation, vous ne revenez jamais. Mieux vaut utiliser 

$(".bet").on('click',function() 
{ //validation 
   if (validated) { 
      $(".bet").off('click'); //prevent to fire again when we are not yet off the page
      //go somewhere
    }
});
0
Pieter van Kampen

Une autre solution que j'ai trouvée était celle-ci, si vous avez plusieurs classes et que vous avez affaire à des boutons radio tout en cliquant sur l'étiquette.

$('.btn').on('click', function(e) {
    e.preventDefault();

    // Hack - Stop Double click on Radio Buttons
    if (e.target.tagName != 'INPUT') {
        // Not a input, check to see if we have a radio
        $(this).find('input').attr('checked', 'checked').change();
    }
});
0
Andrew Vink

https://jsfiddle.net/0vgchj9n/1/

Pour vous assurer que l'événement ne se déclenche qu'une seule fois, vous pouvez utiliser Jquery .one (). JQuery one garantit que votre gestionnaire d'événements n'appelle qu'une seule fois. De plus, vous pouvez inscrire votre gestionnaire d'événements avec un seul pour autoriser d'autres clics une fois le traitement de l'opération de clic en cours terminé.

<div id="testDiv">
  <button class="testClass">Test Button</button>
</div>

var subscribeClickEvent = function() {$("#testDiv").one("click", ".testClass", clickHandler);};

function clickHandler() {
  //... perform the tasks  
  alert("you clicked the button");
  //... subscribe the click handler again when the processing of current click operation is complete  
  subscribeClickEvent();
}

subscribeClickEvent();
0
Razan Paul

J'avais ce problème avec un lien généré dynamiquement:

$(document).on('click', '#mylink', function({...do stuff...});

J'ai trouvé que le remplacement de document par 'body' corrigeait le problème:

$('body').on('click', '#mylink', function({...do stuff...});

0
nateM

Dans mon cas, l’événement onclick se déclenche plusieurs fois car j’ai créé un gestionnaire d’événements générique comparativement à

  `$('div').on("click", 'a[data-toggle="tab"]',function () {
        console.log("dynamic bootstrap tab clicked");
        var href = $(this).attr('href');
        window.location.hash = href;
   });`

changé en

    `$('div#mainData').on("click", 'a[data-toggle="tab"]',function () {
        console.log("dynamic bootstrap tab clicked");
        var href = $(this).attr('href');
        window.location.hash = href;
    });`

et doivent également faire des gestionnaires distincts pour les clics statiques et dynamiques, pour l'onglet statique, cliquez sur

    `$('a[data-toggle="tab"]').on("click",function () {
        console.log("static bootstrap tab clicked");
        var href = $(this).attr('href');
        window.location.hash = href;
    });`
0
Awais Nasir

Essayez comme ça:

<a href="javascript:void(0)" onclick="this.onclick = false; fireThisFunctionOnlyOnce()"> Fire function </a>
0
Adam Kozlowski

Dans mon cas, j'avais chargé deux fois le même fichier *.js sur la page dans une balise <script>; J'ai supprimé la déclaration en double et cela a résolu le problème.

0
inostia