Prevent double submission of forms in jQuery

后端 未结 22 1339
旧时难觅i
旧时难觅i 2020-11-22 08:10

I have a form that takes a little while for the server to process. I need to ensure that the user waits and does not attempt to resubmit the form by clicking the button agai

相关标签:
22条回答
  • 2020-11-22 08:24

    I solved a very similar issue using:

    $("#my_form").submit(function(){
        $('input[type=submit]').click(function(event){
            event.preventDefault();
        });
    });
    
    0 讨论(0)
  • 2020-11-22 08:25

    Modified Nathan's solution a little for Bootstrap 3. This will set a loading text to the submit button. In addition it will timeout after 30 seconds and allow the form to be resubmitted.

    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);
    };
    
    0 讨论(0)
  • 2020-11-22 08:30

    Update in 2018: I just got some points for this old answer, and just wanted to add that the best solution would be to make the operation idempotent so that duplicate submissions are harmless.

    Eg, if the form creates an order, put a unique ID in the form. The first time the server sees an order creation request with that id, it should create it and respond "success". Subsequent submissions should also respond "success" (in case the client didn't get the first response) but shouldn't change anything.

    Duplicates should be detected via a uniqueness check in the database to prevent race conditions.


    I think that your problem is this line:

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

    You're disabling ALL the inputs, including, I'd guess, the ones whose data the form is supposed to submit.

    To disable just the submit button(s), you could do this:

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

    However, I don't think IE will submit the form if even those buttons are disabled. I'd suggest a different approach.

    A jQuery plugin to solve it

    We just solved this problem with the following code. The trick here is using jQuery's data() to mark the form as already submitted or not. That way, we don't have to mess with the submit buttons, which freaks IE out.

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

    Use it like this:

    $('form').preventDoubleSubmission();
    

    If there are AJAX forms that should be allowed to submit multiple times per page load, you can give them a class indicating that, then exclude them from your selector like this:

    $('form:not(.js-allow-double-submission)').preventDoubleSubmission();
    
    0 讨论(0)
  • 2020-11-22 08:30

    There is a possibility to improve Nathan Long's approach. You can replace the logic for detection of already submitted form with this one:

    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
    
    0 讨论(0)
  • 2020-11-22 08:31

    In my case the form's onsubmit had some validation code, so I increment Nathan Long answer including an onsubmit checkpoint

    $.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 讨论(0)
  • 2020-11-22 08:32

    event.timeStamp doesn't work in Firefox. Returning false is non-standard, you should call event.preventDefault(). And while we're at it, always use braces with a control construct.

    To sum up all of the previous answers, here is a plugin that does the job and works 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;
        });
    };
    

    To address Kern3l, the timing method works for me simply because we're trying to stop a double-click of the submit button. If you have a very long response time to a submission, I recommend replacing the submit button or form with a spinner.

    Completely blocking subsequent submissions of the form, as most of the above examples do, has one bad side-effect: if there is a network failure and they want to try to resubmit, they would be unable to do so and would lose the changes they made. This would definitely make an angry user.

    0 讨论(0)
提交回复
热议问题