Prevent double submission of forms in jQuery

JavascriptJqueryDouble Submit-PreventionFormsHttp Post

Javascript Problem Overview


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 again. I tried using the following jQuery code:

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

When I try this in Firefox everything gets disabled but the form is not submitted with any of the POST data it is supposed to include. I can't use jQuery to submit the form because I need the button to be submitted with the form as there are multiple submit buttons and I determine which was used by which one's value is included in the POST. I need the form to be submitted as it usually is and I need to disable everything right after that happens.

Thanks!

Javascript Solutions


Solution 1 - Javascript

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

Solution 2 - Javascript

Timing approach is wrong - how do you know how long the action will take on client's browser?

How to do it

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

When form is submitted it will disable all submit buttons inside.

Remember, in Firefox when you disable a button this state will be remembered when you go back in history. To prevent that you have to enable buttons on page load, for example.

Solution 3 - Javascript

I think Nathan Long's answer is the way to go. For me, I am using client-side validation, so I just added a condition that the form be valid.

EDIT: If this is not added, the user will never be able to submit the form if the client-side validation encounters an error.

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

Solution 4 - Javascript

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.

Solution 5 - Javascript

Please, check out jquery-safeform plugin.

Usage example:

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

Solution 6 - Javascript

> ...but the form is not submitted with > any of the POST data it is supposed to > include.

Correct. Disabled form element names/values will not be sent to the server. You should set them as readonly elements.

Also, anchors cannot be disabled like that. You will need to either remove their HREFs (not recommended) or prevent their default behaviour (better way), e.g.:

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

Solution 7 - Javascript

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

Solution 8 - Javascript

Nathan's code but for jQuery Validate plugin

If you happen to use jQuery Validate plugin, they already have submit handler implemented, and in that case there is no reason to implement more than one. The 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;
    }
  }
});

You can easily expand it within the } else {-block to disable inputs and/or submit button.

Cheers

Solution 9 - Javascript

I ended up using ideas from this post to come up with a solution that is pretty similar to AtZako's version.

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

Using like this:

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

I found that the solutions that didn't include some kind of timeout but just disabled submission or disabled form elements caused problems because once the lock-out is triggered you can't submit again until you refresh the page. That causes some problems for me when doing ajax stuff.

This can probably be prettied up a bit as its not that fancy.

Solution 10 - Javascript

If using AJAX to post a form, set async: false should prevent additional submits before the form clears:

$("#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;
   }
});

Solution 11 - Javascript

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

Solution 12 - Javascript

Use two submit buttons.

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

And jQuery:

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

  

Solution 13 - Javascript

Use simple counter on submit.

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

And call monitor() function on submit the form.

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

Solution 14 - Javascript

You can stop the second submit by this

$("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
	});
});

Solution 15 - Javascript

I've been having similar issues and my solution(s) are as follows.

If you don't have any client side validation then you can simply use the jquery one() method as documented here.

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

This disables the handler after its been invoked.

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

If you're doing client side validation as I was doing then its slightly more tricky. The above example would not let you submit again after failed validation. Try this approach instead

$("#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);
   }
});

Solution 16 - Javascript

All of these solutions are passable as long as you're not importing the jQuery validation plugin.

For example, if the client enters invalid input and submits the form, the button will become disabled regardless of whether jQuery validation detects the invalid input. Then the client won't be able to re-submit the form after fixing their input.

The workaround for this issue only took one if statement:

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

After adding this code to my globally-imported JavaScript file, I was unsuccessful in trying to double-post forms on my website.

Solution 17 - Javascript

this code will display loading on the button label, and set button to

disable state, then after processing, re-enable and return back the original button text**

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

Solution 18 - Javascript

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

Solution 19 - Javascript

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

Solution 20 - Javascript

Change submit button:

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

With normal button:

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

Then use click function:

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

And remember re-enable button when is necesary:

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

Solution 21 - Javascript

I can't believe the good old fashioned css trick of pointer-events: none hasn't been mentioned yet. I had the same issue by adding a disabled attribute but this doesn't post back. Try the below and replace #SubmitButton with the ID of your submit button.

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

Solution 22 - Javascript

Why not just this -- this will submit the form but also disable the submitting button,

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

Also, if you're using jQuery Validate, you can put these two lines under if ($('#myForm').valid()).

Solution 23 - Javascript

The absolute best way I've found is to immediately disable the button when clicked:

$('#myButton').click(function() {
    $('#myButton').prop('disabled', true);
});

And re-enable it when needed, for example:

  • validation failed
  • error while processing the form data by the server, then after an error response using jQuery

Solution 24 - Javascript

I solved a very similar issue using:

$("#my_form").submit(function(){
	$('input[type=submit]').click(function(event){
		event.preventDefault();
	});
});

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAdamView Question on Stackoverflow
Solution 1 - JavascriptNathan LongView Answer on Stackoverflow
Solution 2 - JavascriptCtrl-CView Answer on Stackoverflow
Solution 3 - JavascriptPTKView Answer on Stackoverflow
Solution 4 - JavascriptRobin DaughertyView Answer on Stackoverflow
Solution 5 - JavascriptMax KamenkovView Answer on Stackoverflow
Solution 6 - Javascriptkarim79View Answer on Stackoverflow
Solution 7 - JavascriptMikhail FiadosenkaView Answer on Stackoverflow
Solution 8 - JavascriptSlavaView Answer on Stackoverflow
Solution 9 - JavascriptjacklinView Answer on Stackoverflow
Solution 10 - JavascriptAl KariView Answer on Stackoverflow
Solution 11 - JavascriptAlexZView Answer on Stackoverflow
Solution 12 - Javascriptizmir_LEEView Answer on Stackoverflow
Solution 13 - JavascriptMr. MakView Answer on Stackoverflow
Solution 14 - JavascriptMohammed ZayanView Answer on Stackoverflow
Solution 15 - JavascriptmattblokeView Answer on Stackoverflow
Solution 16 - JavascriptGabeView Answer on Stackoverflow
Solution 17 - JavascriptMohamed.AbdoView Answer on Stackoverflow
Solution 18 - Javascriptuser1672591View Answer on Stackoverflow
Solution 19 - JavascriptbocapioView Answer on Stackoverflow
Solution 20 - JavascriptDaniView Answer on Stackoverflow
Solution 21 - JavascriptTom McDonoughView Answer on Stackoverflow
Solution 22 - Javascriptgene b.View Answer on Stackoverflow
Solution 23 - Javascriptuser2342558View Answer on Stackoverflow
Solution 24 - JavascriptNolanView Answer on Stackoverflow