wake-up-neo.com

Verhindern Sie die doppelte Übermittlung von Formularen in jQuery

Ich habe ein Formular, das vom Server etwas verarbeitet werden muss. Ich muss sicherstellen, dass der Benutzer wartet und nicht versucht, das Formular erneut zu senden, indem Sie erneut auf die Schaltfläche klicken. Ich habe versucht, den folgenden jQuery-Code zu verwenden:

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

Wenn ich dies in Firefox versuche, wird alles deaktiviert, aber das Formular wird nicht mit den POST - Daten übermittelt, die es enthalten soll. Ich kann jQuery nicht zum Senden des Formulars verwenden, weil ich den Button mit dem Formular senden muss, da es mehrere Submit-Buttons gibt und ich bestimme, welcher Wert verwendet wurde, um welchen Wert es sich bei dem POST handelt. Ich muss das Formular so senden, wie es normalerweise ist, und alles muss sofort deaktiviert werden.

Vielen Dank!

153
Adam

Update in 2018: Ich habe gerade einige Punkte für diese alte Antwort erhalten und wollte nur hinzufügen, dass die Lösung best darin besteht, die Operation idempotent zu machen, so dass doppelte Einsendungen harmlos sind.

Wenn das Formular beispielsweise eine Bestellung erstellt, geben Sie eine eindeutige ID in das Formular ein. Wenn der Server zum ersten Mal eine Auftragserstellungsanforderung mit dieser ID sieht, sollte er diese erstellen und auf "Erfolg" antworten. Spätere Einreichungen sollten ebenfalls auf "Erfolg" antworten (falls der Kunde nicht die erste Antwort erhalten hat), aber nichts ändern.

Duplikate sollten über eine Eindeutigkeitsprüfung in der Datenbank ermittelt werden, um Race-Bedingungen zu vermeiden.


Ich denke, dein Problem ist diese Zeile:

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

Sie deaktivieren ALLE Eingaben, einschließlich derjenigen, deren Daten das Formular einreichen soll. 

Um nur die Senden-Schaltfläche (n) zu deaktivieren, führen Sie könnte Folgendes aus:

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

Ich glaube jedoch nicht, dass IE das Formular senden wird, selbst wenn diese Schaltflächen deaktiviert sind. Ich würde einen anderen Ansatz vorschlagen.

Ein jQuery-Plugin, um es zu lösen

Wir haben dieses Problem gerade mit dem folgenden Code gelöst. Der Trick hier ist die Verwendung von jQuery's data(), um das Formular als bereits gesendet zu markieren oder nicht. Auf diese Weise müssen wir uns nicht mit den Submit-Buttons beschäftigen, die ausflippen IE.

// 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;
};

Verwenden Sie es so:

$('form').preventDoubleSubmission();

Wenn es AJAX -Formulare gibt, die sollte mehrmals pro Seite geladen werden dürfen, können Sie ihnen eine Klasse zuweisen, die dies angibt, und sie dann wie folgt aus Ihrem Selektor ausschließen:

$('form:not(.js-allow-double-submission)').preventDoubleSubmission();
295
Nathan Long

Timing-Ansatz ist falsch - woher wissen Sie, wie lange die Aktion im Browser des Kunden dauert?

Wie es geht

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

Wenn das Formular gesendet wird, werden alle darin enthaltenen Schaltflächen deaktiviert.

Denken Sie daran, dass in Firefox beim Deaktivieren einer Schaltfläche dieser Status gespeichert wird, wenn Sie in die Historie zurückkehren. Um dies zu verhindern, müssen Sie beispielsweise Schaltflächen beim Laden der Seite aktivieren.

41
Ctrl-C

Ich denke, dass die Antwort von Nathan Long der Weg ist. Für mich verwende ich die clientseitige Validierung, also habe ich nur die Bedingung hinzugefügt, dass das Formular gültig ist.

EDIT: Wenn dies nicht hinzugefügt wird, kann der Benutzer das Formular niemals absenden, wenn bei der clientseitigen Validierung ein Fehler auftritt.

        // 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
PTK

event.timeStamp funktioniert nicht in Firefox. Die Rückgabe von false ist nicht standardmässig. Sie sollten event.preventDefault() aufrufen. Und während wir gerade dabei sind, verwenden always geschweifte Klammern mit einem Kontrollkonstrukt

Um alle bisherigen Antworten zusammenzufassen, hier ein Plugin, das die Aufgabe erledigt und browserübergreifend arbeitet. 

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;
    });
};

Um Kern3l anzusprechen, funktioniert die Timing-Methode für mich, einfach weil wir versuchen, einen Doppelklick auf die Schaltfläche "Abschicken" zu stoppen. Wenn Sie eine sehr lange Antwortzeit auf eine Übermittlung haben, empfehle ich, die Übermittlungsschaltfläche oder das Formular durch einen Spinner zu ersetzen.

Das vollständige Blockieren nachfolgender Übermittlungen des Formulars hat, wie die meisten der oben genannten Beispiele, einen schlechten Nebeneffekt: Wenn ein Netzwerkausfall auftritt und Sie versuchen möchten, das Formular erneut zu übermitteln, ist dies nicht möglich, und die Änderungen werden dadurch verloren gemacht. Dies würde definitiv einen wütenden Benutzer machen.

9
Robin Daugherty

Bitte überprüfen Sie jquery-safeform plugin. 

Anwendungsbeispiel:

$('.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;
    }
});
8
Max Kamenkov

Es besteht die Möglichkeit, den Ansatz von Nathan Long ..__ zu verbessern. Sie können die Logik zum Erkennen eines bereits gesendeten Formulars durch dieses ersetzen:

var lastTime = $(this).data("lastSubmitTime");
if (lastTime && typeof lastTime === "object") {
    var now = new Date();
    if ((now - lastTime) > 2000) // 2000ms
        return true;
    else
        return false;
}
$(this).data("lastSubmitTime", new Date());
return true; // or do an ajax call or smth else
4

Nathans Code, aber für jQuery Validate Plugin

Wenn Sie das Plugin jQuery Validate verwenden, wurde bereits ein Übergabehandler implementiert. In diesem Fall besteht kein Grund, mehr als einen zu implementieren. Der 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;
    }
  }
});

Sie können es einfach innerhalb des } else {- Blocks erweitern, um die Eingaben und/oder die Schaltfläche zum Senden zu deaktivieren.

Prost

4
Alph.Dev

... aber das Formular wird nicht mit .__ übermittelt. eine der POST - Daten, die es annehmen soll umfassen.

Richtig. Deaktivierte Formularelementnamenwerte werden nicht an den Server gesendet. Sie sollten sie als/- readonly elements festlegen.

Anker können auch nicht so deaktiviert werden. Sie müssen entweder ihre HREFs entfernen (nicht empfohlen) oder ihr Standardverhalten (besserer Weg) verhindern, z.

<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
karim79

Am Ende habe ich Ideen aus diesem Post verwendet, um eine Lösung zu finden, die der von AtZako sehr ähnlich ist.

 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;
  });   
};

Verwendung wie folgt: 

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

Ich habe festgestellt, dass die Lösungen, die keine Art von Zeitlimit enthielten, aber nur die Übermittlung deaktiviert oder Formularelemente deaktiviert hatten, Probleme verursachten, da die Sperrung erst ausgelöst wird, wenn Sie die Seite erst wieder aktualisieren. Das macht mir einige Probleme, wenn ich Ajax-Sachen mache.

Dies kann wahrscheinlich etwas verjüngt werden, da es nicht besonders schick ist.

2
jacklin

Nathans Lösung für Bootstrap 3 ein wenig geändert. Dadurch wird ein Ladetext auf die Schaltfläche "Senden" gesetzt. Außerdem wird nach 30 Sekunden ein Timeout ausgeführt, und das Formular kann erneut gesendet werden.

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
AlexZ

Wenn SieAJAXverwenden, um ein Formular zu veröffentlichen, sollte async: false weitere Übergaben verhindern, bevor das Formular gelöscht wird:

$("#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
Al Kari

so mache ich es:

$(document).ready(function () {
  $('.class_name').click(function () {
    $(this).parent().append('<img src="data:image/gif;base64,R0lGODlhEAAQAPQAAP///wAAAPDw8IqKiuDg4EZGRnp6egAAAFhYWCQkJKysrL6+vhQUFJycnAQEBDY2NmhoaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAAFdyAgAgIJIeWoAkRCCMdBkKtIHIngyMKsErPBYbADpkSCwhDmQCBethRB6Vj4kFCkQPG4IlWDgrNRIwnO4UKBXDufzQvDMaoSDBgFb886MiQadgNABAokfCwzBA8LCg0Egl8jAggGAA1kBIA1BAYzlyILczULC2UhACH5BAkKAAAALAAAAAAQABAAAAV2ICACAmlAZTmOREEIyUEQjLKKxPHADhEvqxlgcGgkGI1DYSVAIAWMx+lwSKkICJ0QsHi9RgKBwnVTiRQQgwF4I4UFDQQEwi6/3YSGWRRmjhEETAJfIgMFCnAKM0KDV4EEEAQLiF18TAYNXDaSe3x6mjidN1s3IQAh+QQJCgAAACwAAAAAEAAQAAAFeCAgAgLZDGU5jgRECEUiCI+yioSDwDJyLKsXoHFQxBSHAoAAFBhqtMJg8DgQBgfrEsJAEAg4YhZIEiwgKtHiMBgtpg3wbUZXGO7kOb1MUKRFMysCChAoggJCIg0GC2aNe4gqQldfL4l/Ag1AXySJgn5LcoE3QXI3IQAh+QQJCgAAACwAAAAAEAAQAAAFdiAgAgLZNGU5joQhCEjxIssqEo8bC9BRjy9Ag7GILQ4QEoE0gBAEBcOpcBA0DoxSK/e8LRIHn+i1cK0IyKdg0VAoljYIg+GgnRrwVS/8IAkICyosBIQpBAMoKy9dImxPhS+GKkFrkX+TigtLlIyKXUF+NjagNiEAIfkECQoAAAAsAAAAABAAEAAABWwgIAICaRhlOY4EIgjH8R7LKhKHGwsMvb4AAy3WODBIBBKCsYA9TjuhDNDKEVSERezQEL0WrhXucRUQGuik7bFlngzqVW9LMl9XWvLdjFaJtDFqZ1cEZUB0dUgvL3dgP4WJZn4jkomWNpSTIyEAIfkECQoAAAAsAAAAABAAEAAABX4gIAICuSxlOY6CIgiD8RrEKgqGOwxwUrMlAoSwIzAGpJpgoSDAGifDY5kopBYDlEpAQBwevxfBtRIUGi8xwWkDNBCIwmC9Vq0aiQQDQuK+VgQPDXV9hCJjBwcFYU5pLwwHXQcMKSmNLQcIAExlbH8JBwttaX0ABAcNbWVbKyEAIfkECQoAAAAsAAAAABAAEAAABXkgIAICSRBlOY7CIghN8zbEKsKoIjdFzZaEgUBHKChMJtRwcWpAWoWnifm6ESAMhO8lQK0EEAV3rFopIBCEcGwDKAqPh4HUrY4ICHH1dSoTFgcHUiZjBhAJB2AHDykpKAwHAwdzf19KkASIPl9cDgcnDkdtNwiMJCshACH5BAkKAAAALAAAAAAQABAAAAV3ICACAkkQZTmOAiosiyAoxCq+KPxCNVsSMRgBsiClWrLTSWFoIQZHl6pleBh6suxKMIhlvzbAwkBWfFWrBQTxNLq2RG2yhSUkDs2b63AYDAoJXAcFRwADeAkJDX0AQCsEfAQMDAIPBz0rCgcxky0JRWE1AmwpKyEAIfkECQoAAAAsAAAAABAAEAAABXkgIAICKZzkqJ4nQZxLqZKv4NqNLKK2/Q4Ek4lFXChsg5ypJjs1II3gEDUSRInEGYAw6B6zM4JhrDAtEosVkLUtHA7RHaHAGJQEjsODcEg0FBAFVgkQJQ1pAwcDDw8KcFtSInwJAowCCA6RIwqZAgkPNgVpWndjdyohACH5BAkKAAAALAAAAAAQABAAAAV5ICACAimc5KieLEuUKvm2xAKLqDCfC2GaO9eL0LABWTiBYmA06W6kHgvCqEJiAIJiu3gcvgUsscHUERm+kaCxyxa+zRPk0SgJEgfIvbAdIAQLCAYlCj4DBw0IBQsMCjIqBAcPAooCBg9pKgsJLwUFOhCZKyQDA3YqIQAh+QQJCgAAACwAAAAAEAAQAAAFdSAgAgIpnOSonmxbqiThCrJKEHFbo8JxDDOZYFFb+A41E4H4OhkOipXwBElYITDAckFEOBgMQ3arkMkUBdxIUGZpEb7kaQBRlASPg0FQQHAbEEMGDSVEAA1QBhAED1E0NgwFAooCDWljaQIQCE5qMHcNhCkjIQAh+QQJCgAAACwAAAAAEAAQAAAFeSAgAgIpnOSoLgxxvqgKLEcCC65KEAByKK8cSpA4DAiHQ/DkKhGKh4ZCtCyZGo6F6iYYPAqFgYy02xkSaLEMV34tELyRYNEsCQyHlvWkGCzsPgMCEAY7Cg04Uk48LAsDhRA8MVQPEF0GAgqYYwSRlycNcWskCkApIyEAOwAAAAAAAAAAAA==" />');
    $(this).hide();
  });
});

credits: https://github.com/phpawy/jquery-submit-once

1
phpawy

Ich hatte ähnliche Probleme und meine Lösungen lauten wie folgt.

Wenn Sie keine clientseitige Validierung haben, können Sie einfach die hier dokumentierte Methode jquery one () verwenden.

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

Dadurch wird der Handler deaktiviert, nachdem er aufgerufen wurde.

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

Wenn Sie die clientseitige Validierung wie ich durchführen, ist es etwas schwieriger. Im obigen Beispiel können Sie nach einer fehlgeschlagenen Überprüfung nicht erneut senden. Versuchen Sie stattdessen diesen Ansatz

$("#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
mattbloke

Verwenden Sie zwei Senden-Schaltflächen.

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

Und jQuery:

$("#sub").click(function(){
  $(this).val("Please wait..");
  $(this).attr("disabled","disabled");
  $("#sub2").click();
});
1
izmir_LEE

Schaltfläche "Senden" ändern:

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

Mit normaler Taste:

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

Dann nutzen Sie die Klickfunktion:

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

Denken Sie daran, die Schaltfläche zum erneuten Aktivieren zu aktivieren, wenn dies erforderlich ist:

$('#submitButtonId').prop('disabled', false);
0
Dani

Ich kann den guten altmodischen CSS-Trick von Zeigerereignissen nicht glauben: Noch wurde nichts erwähnt. Ich hatte das gleiche Problem, indem ich ein deaktiviertes Attribut hinzufügte, aber dies wird nicht zurückgegeben. Versuchen Sie es unten und ersetzen Sie #SubmitButton durch die ID Ihres Submit-Buttons.

$(document).on('click', '#SubmitButton', function () {
    $(this).css('pointer-events', 'none');
})
0
Tom McDonough

Warum nicht einfach das? Dadurch wird das Formular gesendet, aber auch die Schaltfläche zum Senden deaktiviert.

   $('#myForm').on('submit', function(e) {
       var clickedSubmit = $(this).find('input[type=submit]:focus');
       $(clickedSubmit).prop('disabled', true);
   });

Wenn Sie jQuery Validate verwenden, können Sie diese beiden Zeilen auch unter if ($('#myForm').valid()) setzen.

0
gene b.

Meine Lösung:

// 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
user1672591

Sie können die zweite Übermittlung auf diese Weise stoppen

$("form").submit(function() {
        // submit more than once return false
        $(this).submit(function() {
            return false;
        });
        // submit once return true
        return true; // or do what you want to do
    });
});
0
Mohammed Zayan

Verwenden Sie beim Senden einen einfachen Zähler.

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

Und rufen Sie die Funktion monitor() auf, wenn Sie das Formular absenden.

    <form action="/someAction.go" onsubmit="return monitor();" method="POST">
        ....
        <input type="submit" value="Save Data">
    </form>
0
Mr. Mak

In meinem Fall hatte das Onsubmit des Formulars einen Validierungscode, sodass ich Nathan Long Antwort einschließlich eines Onsubmit-Prüfpunkts inkrementiere 

$.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
bocapio

dieser Code zeigt das Laden auf der Schaltflächenbeschriftung an und setzt die Schaltfläche auf

deaktivieren Sie den Status und aktivieren Sie nach der Verarbeitung den ursprünglichen Schaltflächentext erneut. **

$(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
Mohamed.Abdo