Javascript 防止在 jQuery 中重复提交表单
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2830542/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Prevent double submission of forms in jQuery
提问by Adam
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:
我有一个需要服务器处理一段时间的表单。我需要确保用户等待并且不会尝试通过再次单击按钮来重新提交表单。我尝试使用以下 jQuery 代码:
<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.
当我在 Firefox 中尝试此操作时,所有内容都被禁用,但表单未与它应该包含的任何 POST 数据一起提交。我无法使用 jQuery 提交表单,因为我需要将按钮与表单一起提交,因为有多个提交按钮,并且我确定 POST 中包含哪个值。我需要像往常一样提交表单,并且我需要在发生这种情况后立即禁用所有内容。
Thanks!
谢谢!
回答by Nathan Long
Update in 2018: I just got some points for this old answer, and just wanted to add that the bestsolution would be to make the operation idempotent so that duplicate submissions are harmless.
2018 年更新:我刚刚从这个旧答案中得到了一些分数,只是想补充一点,最好的解决方案是使操作具有幂等性,以便重复提交是无害的。
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.
例如,如果表单创建了一个订单,则在表单中放置一个唯一的 ID。服务器第一次看到带有该 id 的订单创建请求时,它应该创建它并响应“成功”。随后的提交也应该响应“成功”(以防客户没有得到第一个响应)但不应该改变任何东西。
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 coulddo 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.
但是,我认为即使这些按钮被禁用,IE 也不会提交表单。我建议采用不同的方法。
A jQuery plugin to solve it
一个jQuery插件来解决它
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.
我们刚刚用下面的代码解决了这个问题。这里的技巧是使用 jQuerydata()来标记表单是否已经提交。这样,我们就不必弄乱提交按钮,这让 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;
};
Use it like this:
像这样使用它:
$('form').preventDoubleSubmission();
If there are AJAX forms that shouldbe allowed to submit multiple times per page load, you can give them a class indicating that, then exclude them from your selector like this:
如果有应该允许每次页面加载多次提交的AJAX 表单,您可以给它们一个指示这一点的类,然后将它们从您的选择器中排除,如下所示:
$('form:not(.js-allow-double-submission)').preventDoubleSubmission();
回答by Ctrl-C
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.
请记住,在 Firefox 中,当您禁用按钮时,该状态将在您返回历史记录时被记住。例如,为了防止您必须在页面加载时启用按钮。
回答by PTK
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.
我认为 Nathan Long 的答案是要走的路。对我来说,我使用的是客户端验证,所以我只是添加了表单有效的条件。
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;
};
回答by Robin Daugherty
event.timeStampdoesn't work in Firefox. Returning false is non-standard, you should call event.preventDefault(). And while we're at it, alwaysuse braces with a control construct.
event.timeStamp在 Firefox 中不起作用。返回 false 是非标准的,您应该调用event.preventDefault(). 当我们这样做时,请始终使用带有控制结构的大括号。
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.
为了解决 Kern3l,计时方法对我有用,因为我们试图停止双击提交按钮。如果您对提交的响应时间很长,我建议用微调器替换提交按钮或表单。
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.
完全阻止表单的后续提交,就像上面的大多数例子一样,有一个不好的副作用:如果出现网络故障并且他们想尝试重新提交,他们将无法这样做并且会丢失他们所做的更改制作。这肯定会让用户生气。
回答by Max Kamenkov
Please, check out jquery-safeformplugin.
请查看jquery-safeform插件。
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;
}
});
回答by Mikhail Fiadosenka
There is a possibility to improve Nathan Long's approach. You can replace the logic for detection of already submitted form with this one:
有可能改进 Nathan Long 的方法。您可以用这个替换检测已提交表单的逻辑:
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
回答by Alph.Dev
Nathan's code but for jQuery Validate plugin
Nathan 的代码,但用于 jQuery Validate 插件
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 Validate 插件,他们已经实现了提交处理程序,在这种情况下,没有理由实现多个。编码:
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.
您可以轻松地在} else {-block 中展开它以禁用输入和/或提交按钮。
Cheers
干杯
回答by karim79
...but the form is not submitted with any of the POST data it is supposed to include.
...但该表单没有提交它应该包含的任何 POST 数据。
Correct. Disabled form element names/values will not be sent to the server. You should set them as readonlyelements.
正确的。禁用的表单元素名称/值将不会发送到服务器。您应该将它们设置为只读元素。
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.:
此外,锚不能像那样被禁用。您将需要删除他们的 HREF(不推荐)或阻止他们的默认行为(更好的方式),例如:
<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>
回答by Al Kari
If using AJAXto post a form, set async: falseshould prevent additional submits before the form clears:
如果使用AJAX发布表单,则 setasync: false应在表单清除之前阻止其他提交:
$("#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;
}
});
回答by Hymanlin
I ended up using ideas from this post to come up with a solution that is pretty similar to AtZako's version.
我最终使用这篇文章中的想法提出了一个与 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;
});
};
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.
我发现不包含某种超时但仅禁用提交或禁用表单元素的解决方案会导致问题,因为一旦触发锁定,您就无法再次提交,直到刷新页面。在做 ajax 的时候,这给我带来了一些问题。
This can probably be prettied up a bit as its not that fancy.
这可能可以美化一点,因为它不是那么花哨。

