Éviter la double soumission des formulaires en jQuery

j'ai un formulaire qui prend un peu de temps pour le serveur. Je dois m'assurer que l'utilisateur attend et ne tente pas de soumettre à nouveau le formulaire en cliquant de nouveau sur le bouton. J'ai essayé d'utiliser le code jQuery suivant:

<script type="text/javascript">
$(document).ready(function() {
    $("form#my_form").submit(function() {
        $('input').attr('disabled', 'disabled');
        $('a').attr('disabled', 'disabled');
        return true;
    });
});
</script>

quand J'essaie cela dans Firefox, tout est désactivé mais le formulaire n'est pas soumis avec les données POST qu'il est censé inclure. Je ne peux pas utiliser jQuery pour soumettre le formulaire parce que j'ai besoin que le bouton soit soumis avec le forme puisqu'il y a plusieurs boutons de soumission et je déterminer qui a été utilisée par lequel la valeur est incluse dans le POSTE. J'ai besoin que le formulaire soit soumis tel qu'il est habituellement et j'ai besoin de tout désactiver juste après que cela arrive.

Merci!

139
demandé sur smholloway 2010-05-14 01:45:02

20 réponses

je pense que votre problème est cette ligne:

$('input').attr('disabled','disabled');

vous désactivez toutes les entrées, y compris, je suppose, celles dont les données que le formulaire est censé soumettre.

pour désactiver juste le(S) bouton (s) soumettre, vous pourrait faire ceci:

$('button[type=submit], input[type=submit]').prop('disabled',true);

cependant, je ne pense pas QU'IE soumettra le formulaire si même ces boutons sont désactivés. Je suggère une autre approche.

un plugin jQuery pour le résoudre

nous venons de résoudre ce problème avec le code suivant. L'astuce ici est d'utiliser le data() de jQuery pour marquer le formulaire comme déjà soumis ou non. Comme ça, on n'a pas à jouer avec les boutons soumettre, ce qui fait flipper.

// jQuery plugin to prevent double submission of forms
jQuery.fn.preventDoubleSubmission = function() {
  $(this).on('submit',function(e){
    var $form = $(this);

    if ($form.data('submitted') === true) {
      // Previously submitted - don't submit again
      e.preventDefault();
    } else {
      // Mark it so that the next submit can be ignored
      $form.data('submitted', true);
    }
  });

  // Keep chainability
  return this;
};

utilisez - le comme ceci:

$('form').preventDoubleSubmission();

S'il y a des formulaires AJAX que devrait devrait être autorisé à soumettre plusieurs fois par page load, vous pouvez leur donner une classe indiquant que, puis les exclure de votre sélecteur comme ceci:

$('form:not(.js-allow-double-submission)').preventDoubleSubmission();
275
répondu Nathan Long 2016-04-21 12:46:02

L'approche temporelle est erronée-comment savez-vous combien de temps l'action prendra sur le navigateur du client?

Comment faire

$('form').submit(function(){
  $(this).find(':submit').attr('disabled','disabled');
});

lorsque le formulaire est soumis, il désactivera tous les boutons soumettre à l'intérieur.

rappelez-vous, dans Firefox quand vous désactivez un bouton cet état sera rappelé lorsque vous retournez dans l'histoire. Pour éviter cela, vous devez activer les boutons sur la page de chargement, par exemple.

38
répondu Ctrl-C 2013-07-19 07:23:54

je pense que la réponse de Nathan Long est la voie à suivre. Pour moi, j'utilise la validation côté client, donc j'ai juste ajouté une condition que le formulaire soit valide.

EDIT : Si ceci n'est pas ajouté, l'utilisateur ne pourra jamais soumettre le formulaire si la validation côté client rencontre une erreur.

        // jQuery plugin to prevent double submission of forms
        jQuery.fn.preventDoubleSubmission = function () {
            $(this).on('submit', function (e) {
                var $form = $(this);

                if ($form.data('submitted') === true) {
                    // Previously submitted - don't submit again
                    alert('Form already submitted. Please wait.');
                    e.preventDefault();
                } else {
                    // Mark it so that the next submit can be ignored
                    // ADDED requirement that form be valid
                    if($form.valid()) {
                        $form.data('submitted', true);
                    }
                }
            });

            // Keep chainability
            return this;
        };
19
répondu PTK 2015-02-04 22:27:07

event.timeStamp ne fonctionne pas dans Firefox. Retourner false n'est pas standard, vous devez appeler event.preventDefault() . Et pendant que nous y sommes, "toujours utilisez des entretoises avec une construction de contrôle .

pour résumer toutes les réponses précédentes, voici un plugin qui fait le travail et fonctionne cross-browser.

jQuery.fn.preventDoubleSubmission = function() {

    var last_clicked, time_since_clicked;

    jQuery(this).bind('submit', function(event) {

        if(last_clicked) {
            time_since_clicked = jQuery.now() - last_clicked;
        }

        last_clicked = jQuery.now();

        if(time_since_clicked < 2000) {
            // Blocking form submit because it was too soon after the last submit.
            event.preventDefault();
        }

        return true;
    });
};

pour adresser Kern3l, la méthode de chronométrage fonctionne pour moi tout simplement parce que nous essayons d'arrêter un double-cliquez sur le bouton "soumettre". Si vous avez un très long délai de réponse à une soumission, je vous recommande de remplacer le bouton Soumettre ou le formulaire par une broche.

le fait de bloquer complètement les soumissions subséquentes du formulaire, comme le font la plupart des exemples ci-dessus, a un mauvais effet secondaire: s'il y a une défaillance du réseau et qu'ils veulent essayer de soumettre de nouveau, ils ne seraient pas en mesure de le faire et perdraient les changements qu'ils ont faits. Cela ferait certainement un utilisateur en colère.

8
répondu Robin Daugherty 2017-04-12 07:31:17

s'il vous Plaît, consultez jquery-safeform plugin.

exemple d'utilisation:

$('.safeform').safeform({
    timeout: 5000,  // disable next submission for 5 sec
    submit: function() {
        // You can put validation and ajax stuff here...

        // When done no need to wait for timeout, re-enable the form ASAP
        $(this).safeform('complete');
        return false;
    }
});
7
répondu Maxim Kamenkov 2015-01-19 23:18:01

...mais le formulaire n'est pas soumis à toutes les données POST qu'il est censé comprendre.

Correct. Les noms/valeurs d'éléments de formulaire désactivés ne seront pas envoyés au serveur. Vous devez les définir comme readonly éléments.

aussi, les ancres ne peuvent pas être désactivées comme ça. Vous aurez besoin soit de supprimer leurs href (non recommandé) ou d'empêcher leur comportement par défaut( meilleure façon), par exemple:

<script type="text/javascript">
$(document).ready(function(){
    $("form#my_form").submit(function(){
      $('input').attr('readonly', true);
      $('input[type=submit]').attr("disabled", "disabled");
      $('a').unbind("click").click(function(e) {
          e.preventDefault();
          // or return false;
      });
    });
</script>
4
répondu karim79 2010-05-13 22:15:15

code de Nathan mais pour jQuery valider plugin

si vous utilisez jQuery Validate plugin, ils ont déjà submit handler implémenté, et dans ce cas il n'y a aucune raison d'implémenter plus d'un plugin. Le code:

jQuery.validator.setDefaults({
  submitHandler: function(form){
    // Prevent double submit
    if($(form).data('submitted')===true){
      // Previously submitted - don't submit again
      return false;
    } else {
      // Mark form as 'submitted' so that the next submit can be ignored
      $(form).data('submitted', true);
      return true;
    }
  }
});

vous pouvez facilement l'étendre dans le bloc } else { - pour désactiver les entrées et/ou soumettre le bouton.

Cheers

3
répondu Alph.Dev 2015-04-21 09:14:45

j'ai fini par utiliser les idées de ce post pour trouver une solution qui est assez similaire à la version D'AtZako.

 jQuery.fn.preventDoubleSubmission = function() {

    var last_clicked, time_since_clicked;

    $(this).bind('submit', function(event){

    if(last_clicked) 
      time_since_clicked = event.timeStamp - last_clicked;

    last_clicked = event.timeStamp;

    if(time_since_clicked < 2000)
      return false;

    return true;
  });   
};

en utilisant comme ceci:

$('#my-form').preventDoubleSubmission();

j'ai trouvé que les solutions qui n'incluaient pas une sorte de timeout mais juste une soumission désactivée ou des éléments de formulaire désactivés ont causé des problèmes parce qu'une fois le lock-out déclenché vous ne pouvez pas soumettre à nouveau jusqu'à ce que vous rafraîchissez la page. Cela me pose des problèmes quand je fais des trucs ajax.

cela peut probablement être mis en place un peu comme il n'est pas si fantaisiste.

2
répondu jacklin 2012-06-12 04:07:11

si vous utilisez AJAX pour afficher un formulaire, mettez async: false devrait empêcher les soumissions supplémentaires avant que le formulaire se dégage:

$("#form").submit(function(){
    var one = $("#one").val();
    var two = $("#two").val();
    $.ajax({
      type: "POST",
      async: false,  // <------ Will complete submit before allowing further action
      url: "process.php",
      data: "one="+one+"&two="+two+"&add=true",
      success: function(result){
        console.log(result);
        // do something with result
      },
      error: function(){alert('Error!')}
    });
    return false;
   }
});
2
répondu Al Kari 2013-06-22 06:01:45

a modifié un peu la solution de Nathan pour Bootstrap 3. Cela va définir un texte de chargement sur le bouton Soumettre. De plus, il sera temporisé après 30 secondes et permettra au formulaire d'être soumis à nouveau.

jQuery.fn.preventDoubleSubmission = function() {
  $('input[type="submit"]').data('loading-text', 'Loading...');

  $(this).on('submit',function(e){
    var $form = $(this);

    $('input[type="submit"]', $form).button('loading');

    if ($form.data('submitted') === true) {
      // Previously submitted - don't submit again
      e.preventDefault();
    } else {
      // Mark it so that the next submit can be ignored
      $form.data('submitted', true);
      $form.setFormTimeout();
    }
  });

  // Keep chainability
  return this;
};

jQuery.fn.setFormTimeout = function() {
  var $form = $(this);
  setTimeout(function() {
    $('input[type="submit"]', $form).button('reset');
    alert('Form failed to submit within 30 seconds');
  }, 30000);
};
2
répondu AlexZ 2014-06-07 23:51:19

utilisez deux boutons soumettre.

<input id="sub" name="sub" type="submit" value="OK, Save">
<input id="sub2" name="sub2" type="submit" value="Hidden Submit" style="display:none">

et jQuery:

$("#sub").click(function(){
  $(this).val("Please wait..");
  $(this).attr("disabled","disabled");
  $("#sub2").click();
});
1
répondu izmir_LEE 2015-04-18 11:07:30

j'ai eu des problèmes similaires et ma ou mes solutions sont les suivantes.

si vous n'avez pas de validation côté client, alors vous pouvez simplement utiliser la méthode jquery one() comme documentée ici.

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

ceci désactive le handler après qu'il ait été invoqué.

$("#mysavebuttonid").on("click", function () {
  $('form').submit();
});

si vous faites la validation côté client comme je le faisais alors c'est un peu plus délicat. L'exemple ci-dessus ne vous permettrait pas de soumettre à nouveau après un échec de la validation. Essayez plutôt cette approche

$("#mysavebuttonid").on("click", function (event) {
  $('form').submit();
  if (boolFormPassedClientSideValidation) {
        //form has passed client side validation and is going to be saved
        //now disable this button from future presses
        $(this).off(event);
   }
});
1
répondu mattbloke 2015-08-18 15:04:10

voici comment je fais:

$(document).ready(function () {
  $('.class_name').click(function () {
    $(this).parent().append('<img src="data:image/gif;base64,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" />');
    $(this).hide();
  });
});

crédits: https://github.com/phpawy/jquery-submit-once

1
répondu phpawy 2016-07-11 11:41:33

ce code affichera le chargement sur l'étiquette du bouton, et le bouton de réglage à

désactivation de l'état, puis, après traitement, de le ré-activer et retourner l'original du texte du bouton**

$(function () {

    $(".btn-Loading").each(function (idx, elm) {
        $(elm).click(function () {
            //do processing
            if ($(".input-validation-error").length > 0)
                return;
            $(this).attr("label", $(this).text()).text("loading ....");
            $(this).delay(1000).animate({ disabled: true }, 1000, function () {
                //original event call
                $.when($(elm).delay(1000).one("click")).done(function () {
                    $(this).animate({ disabled: false }, 1000, function () {
                        $(this).text($(this).attr("label"));
                    })
                });
                //processing finalized
            });
        });
    });
    // and fire it after definition
}

);

0
répondu Mohamed.Abdo 2014-03-18 15:07:05

ma solution:

// jQuery plugin to prevent double submission of forms
$.fn.preventDoubleSubmission = function () {
    var $form = $(this);

    $form.find('[type="submit"]').click(function () {
        $(this).prop('disabled', true);
        $form.submit();
    });

    // Keep chainability
    return this;
};
0
répondu 2015-08-17 09:54:24

dans mon cas, l'onsubmit du formulaire avait un code de validation, donc je incrémente Nathan Long réponse incluant un point de contrôle de l'onsubmit

$.fn.preventDoubleSubmission = function() {
      $(this).on('submit',function(e){
        var $form = $(this);
        //if the form has something in onsubmit
        var submitCode = $form.attr('onsubmit');
        if(submitCode != undefined && submitCode != ''){
            var submitFunction = new Function (submitCode);
            if(!submitFunction()){
                event.preventDefault();
                return false;
            }                   
        }

        if ($form.data('submitted') === true) {
            /*Previously submitted - don't submit again */
            e.preventDefault();
        } else {
          /*Mark it so that the next submit can be ignored*/
          $form.data('submitted', true);
        }
      });

      /*Keep chainability*/
      return this;
    };
0
répondu bocapio 2017-05-23 11:54:41

modifier le bouton Soumettre:

<input id="submitButtonId" type="submit" value="Delete" />

avec le bouton normal:

<input id="submitButtonId" type="button" value="Delete" />

puis utiliser la fonction de clic:

$("#submitButtonId").click(function () {
        $('#submitButtonId').prop('disabled', true);
        $('#myForm').submit();
    });

et n'oubliez pas le bouton re-enable quand il est nécessaire:

$('#submitButtonId').prop('disabled', false);
0
répondu Dani 2017-11-23 15:10:17

Utilisation simple compteur sur "soumettre".

    var submitCounter = 0;
    function monitor() {
        submitCounter++;
        if (submitCounter < 2) {
            console.log('Submitted. Attempt: ' + submitCounter);
            return true;
        }
        console.log('Not Submitted. Attempt: ' + submitCounter);
        return false;
    }

et appeler la fonction monitor() sur soumettre le formulaire.

    <form action="/someAction.go" onsubmit="return monitor();" method="POST">
        ....
        <input type="submit" value="Save Data">
    </form>
0
répondu Mr. Mak 2018-05-28 08:31:19

j'ai résolu un problème très similaire en utilisant:

$("#my_form").submit(function(){
    $('input[type=submit]').click(function(event){
        event.preventDefault();
    });
});
-1
répondu Nolan 2011-07-13 19:17:10