web-dev-qa-db-fra.com

Comment empêcher l'appel du gestionnaire d'événement en deux fois lors de clics rapides?

Il y a un bouton et lorsque l'utilisateur clique sur le bouton, certaines données sont sauvegardées dans le back-end. Le problème survient lorsque l'utilisateur clique sur le bouton très rapidement, le gestionnaire d'événements est exécuté plusieurs fois.

C'est le code

var x = 1;
$('#button').click(function() {
  // Do something
  // Save some data on network
  x++;
  console.log(x);
});

Je veux que ce gestionnaire soit exécuté lorsque l'utilisateur clique sur le bouton une seule fois. Même en cas de double ou triple clic, ceci ne devrait être exécuté qu'une fois. Je veux juste éviter les clics rapides, ce gestionnaire peut être exécuté à nouveau ofcourse

J'ai plusieurs solutions dans mon esprit comme

  1. Définissez une variable globale telle que IS_BUTTON_HANDLER_WORKING = false et, lorsque vous entrez le gestionnaire, définissez-la sur true et définissez-la à nouveau sur false. Et vérifiez si c'est vrai, revenez de la fonction.

  2. Détachez le gestionnaire au début et rattachez-le à la fin.

Considérez que vous avez 25 boutons dans votre application. Quelle devrait être la meilleure approche pour mettre cela en œuvre?.

Jetez un coup d'oeil à ceci Fiddle

Solution

$('#button').click(function() {
   $(this).attr('disabled', true);
  // Do something
  // Save some data on network
  $(this).removeAttr('disabled');
});

En utilisant cela, nous sommes sûrs que notre prochain gestionnaire ne sera exécuté que lorsque l'exécution précédente aura été complètement terminée.

13
sachinjain024

David Walsh a une excellente solution .

// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading Edge, instead of the trailing.
function debounce(func, wait, immediate) {
    var timeout;
    return function() {
        var context = this, args = arguments;
        var later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
};
12
Dorad

Il y a plusieurs façons de gérer cela:

Vous pouvez disable/hide le bouton après le clic:

$('#button').attr("disabled", true);

Vous pouvez également définir un délai d'expiration à chaque clic pour vous assurer qu'il ne s'exécutera pas à nouveau:

var x, y = 1;

$('#button').click(function() {
  if (x) clearTimeout(x);
  x = setTimeout(function() {
     // do the work here
     y++;
     console.log(y);
     // ----------------
  }, 1000);
});

Ainsi, chaque fois que le bouton est cliqué, le code ne sera exécuté qu'après un 1000 milliseconds; si le bouton est cliqué en succession rapide, le délai est simplement effacé et recommencé.

notez que ce qui précède n'a pas été testé

Personnellement, je pense que la solution désactivée est la meilleure, car elle indique à l'utilisateur qu'il a cliqué et que quelque chose se passe, vous pouvez même afficher un chargeur à côté du bouton.

8
epoch

Selon modification

Vous devriez utiliser .one ()

ou

Vous pouvez unbind event on click function

var x = 1;
function myButtonClick() {

    $('#button').unbind('click');

    // Do something
    // Save some data on network
    x++;
    console.log(x);
    $('#button').bind('click', myButtonClick);
}

$('#button').bind('click', myButtonClick);
4
Satpal

J'utilise la solution simple ci-dessous et cela fonctionne bien pour moi: 

var x = 1;
e.handled=false;
$('#button').click(function(e) {
  if(e.handled==false){
      e.handled=true;
      // Do something
      // Save some data on network
      x++;
      console.log(x);      
  }
});
1
Roy M J

Vous recherchez ceci

$( "button" ).one( "click", function(evt) {
  x++;
  console.log(x);
});

Ou si vous avez besoin d’un certain intervalle de temps entre deux clics effectifs.

var last, diff;
$( "button" ).click(function( event ) {
  if (last){
    diff = event.timeStamp - last;
    if (diff >= SOMEVAL){
      x++;
      console.log(x);    
    }
  }
  last = event.timeStamp;          
});
1
Ishank Dubey

var btn = document.querySelector('#twofuns');
btn.addEventListener('click',method1);
btn.addEventListener('click',method2);
function method2(){
  console.log("Method 2");
}
setTimeout(function(){
  btn.removeEventListener('click',method1);
},5000);
function method1(){
  console.log("Method 1");
}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>Pramod Kharade-RemoveEventListener after Interval</title>
</head>
<body>
<button id="twofuns">Click Me!</button>
</body>
</html>

Vous pouvez supprimer un auditeur parmi plusieurs dans le script Java, comme ci-dessus.

1
Pramod Kharade

Vous pouvez utiliser jQuery one () méthode comme indiqué ici

1
Vinayak Sakhare

Essayez le code suivant

var x = 1;
var fewSeconds=10; /*10 seconds*/

$('#button').click(function() {
$('#button').attr("disabled", "disabled");
  x++;
  console.log(x);
    var btn = $(this);
    btn.prop('disabled', true);
    setTimeout(function(){
        btn.prop('disabled', false);
    }, fewSeconds*1000);

});
0
Zword

En supposant que vous attachiez et que vous écoutiez les événements au bouton, vous pouvez supprimer l’écouteur d’événements du bouton et le relier si nécessaire.
Dans la fonction d’écoute d’événement, ajoutez le code suivant:

function handleButtonClick(e){
  e.target.removeEventListener("click", handleBackButton);
}

Selon votre configuration, cela pourrait fonctionner.

0
Wigglepee