[英]Disable button on form submission but post button value
我想防止多个表单提交,但我需要将提交元素的值回发到服务器(以便我知道用户单击了哪个按钮)。
大多数关于抑制多个表单提交的互联网智慧似乎涉及在表单提交期间禁用提交按钮。 这可以防止按钮被第二次单击,但也可以防止其值被发布。
我发现了一些隐藏提交按钮的 JS 代码示例,这些按钮允许发布它们的值。 但是这些示例都用某种“正在处理...”消息替换了(现在隐藏的)按钮。 我真的想要一个解决方案,为用户提供一个禁用的按钮,但仍然发布按钮值。
我应该补充一点,我更喜欢一种适用于大多数形式的标准 HTML 的解决方案。 没有神奇的 IFrame、隐藏字段、id 或类名等。我想要一个 JS 函数,我可以藏在一个库中,并从我现有的所有表单中引用以启用这种新行为。
(我有一个解决方案,我将其作为答案发布。但我不得不提出问题以符合 SO 的 Zen。)
这是对如何处理防止用户多次单击表单提交按钮的问题的(又一个)答案。 此解决方案使该按钮似乎已被禁用。
在幕后,它创建了一个禁用按钮以显示给用户,并隐藏实际按钮以便发布其值。 我还移动了隐藏的按钮,这样额外的元素就不会弄乱 CSS 选择器。
还要注意检查无效表单字段。 如果您省略此检查,并且表单验证失败,那么用户最终会收到一个未发布的表单(因为客户端验证失败),但按钮被禁用。
// Disables buttons when form is submitted
$('form').submit(function () {
// Bail out if the form contains validation errors
if ($.validator && !$(this).valid()) return;
var form = $(this);
$(this).find('input[type="submit"], button[type="submit"]').each(function (index) {
// Create a disabled clone of the submit button
$(this).clone(false).removeAttr('id').prop('disabled', true).insertBefore($(this));
// Hide the actual submit button and move it to the beginning of the form
$(this).hide();
form.prepend($(this));
});
});
因为您可以通过其他方式提交表单而不是简单地单击提交按钮,所以最好为表单的提交事件而不是提交按钮上的单击事件添加侦听器。 这个 jQuery 事件侦听器应该适用于任何表单并防止它被多次提交。
$('form').on('submit', function(e) {
if (!$(this).data('submitted')) {
$(this).data('submitted', true);
}
else {
e.preventDefault();
}
});
要使表单看起来被禁用,您可以添加一些使表单看起来被禁用的 css,然后在表单提交时添加类名。
$('form').on('submit', function(e) {
if (!$(this).data('submitted')) {
$(this).data('submitted', true).addClass('disabled');
}
else {
e.preventDefault();
}
});
您可以模拟禁用的外观行为。 例如,如果你有一个这样的按钮:
<input id="btn" type="button" onclick="disableMe(this)" value="Submit" />
你可以像这样定义 CSS
.disabled {
backround-color:grey;
color:darkgrey;
}
和这样的 JS
function disableMe(btn) {
btn.className = "disabled";
btn.onclick = function(){return false}
}
会发生什么 - 第一次单击按钮将变为灰色(通过应用的 CSS)并且 onclick 事件将更改为“返回 false”,以便所有连续调用阻止将来的单击操作。 该按钮将出现并作为禁用,但不会,因此它不会阻止按钮提交。
我想通过双击提交按钮或按两次回车键来阻止用户导致多个表单提交。 我喜欢这个解决方案,因为它不需要隐藏表单字段或隐藏提交按钮。
两个关键点是:
返回 true/false 而不是使用 e.preventDefault() 和 form.submit(),因为 form.submit() 不知道点击了哪个按钮,因此无法传递按钮名称/值。
使用pointer-events: none;
禁用按钮pointer-events: none;
而不是disabled="disabled"
,因为 disabled 属性不会发送按钮名称/值。 我相信pointer-events: none;
Internet Explorer 10 或更低版本不支持。
javascript/jquery 代码:
var form_selector = 'form',
button_selector = 'button, input[type=submit], input[type=button], input[type=reset]',
deactivated_classname = 'state-submitting',
deactivated_class = '.'+'state-submitting';
// Capture the submit event so it will handle both the
// enter key and clicking the submit button.
$(document).on('submit', form_selector, function(e) {
var form = e.target,
buttons = $( form ).find( button_selector );
// Returns, because the form is already being submitted by a previous attempt.
if( $( form ).find( deactivated_class ).length > 0 ) return false;
disableButtons( buttons );
// Safari (version 11) bugfix: Safari needs a timeout or it won't
// show the deactivated styles.
setTimeout(function() {
// Must use return true, because using form.submit(), won't pass the button value.
return true;
}, 50 );
});
function disableButtons( buttons ) {
// Disables all buttons in the form.
$( buttons ).each(function( index, elem ) {
$( elem ).addClass( deactivated_classname );
});
}
对于 AJAX 表单,您需要在返回响应后重新启用按钮。
$( document ).on( 'ajax:complete', form_selector, function(e) {
var form = e.target,
buttons = $( form ).find( button_selector );
enableButtons( buttons );
});
function enableButtons( buttons ) {
$( buttons ).each(function( index, elem ) {
$( elem ).removeClass( deactivated_classname );
});
}
CSS:
// The button is disabled while it is submitting.
.state-submitting {
// Turns off hover and click events. Not supported in IE 10 and below.
pointer-events: none;
opacity: 0.5;
}
这里有几个选项:
1. 您可以创建隐藏输入并在提交表单之前动态更改它的值,无论是 onClick 还是 onHover 所述按钮:
2. 您可以创建一个隐藏的 iframe,它是上述表单的目标。 单击提交按钮后,您可以取消提交事件,获取所有数据并通过 iframe 以编程方式发送。
我遇到了与 OP 相同的问题,我发现通过setTimeout
在短暂(可能是 0 秒)超时后禁用提交按钮可以解决问题。 提交按钮的名称值仍然根据需要与表单数据的其余部分一起发布,但该按钮(几乎)立即禁用自身,防止进一步单击。
超时有点难看,但似乎比更精细的交换/覆盖方案更可取。
这可以与更改表单的onsubmit
属性相结合以进行额外的预防,但为了清楚起见,我没有在下面的示例中这样做。 无论哪种方式,我都喜欢在第一次提交点击后禁用按钮的外观/行为……用户体验对我来说似乎更好……更清楚发生了什么。
我的表单元素的开始标签:
<form onsubmit="return formSubmit(this);" method="post" action="">
在我的 JavaScript 中(抱歉,我不了解最新的 JS 技术,如 jQuery 等,所以我将其发布在老式原生 JavaScript-5-with-no-dependencies-compatible 代码中):
function formSubmit(form) {
// MUST DELAY so as not to break input/button[type=submit] name submission
setTimeout(function () {
var els = form.elements;
for (var i = 0; i < els.length; i++) {
var el = els[i];
if (el.getAttribute('type') == 'submit') {
el.setAttribute('disabled', 'disabled');
}
}
}, 0);
return true;
}
我认为更好的解决方案是使用 JQuery :
<form onsubmit="$('#submit').hide();" method="post" action="">
没有机会双击。 有时我们在提交按钮中使用名称字段进行验证,因此如果禁用此功能,则可能会失败。 使用 .hide() 按钮将被隐藏。 所以没有机会双击它。
老实说,我无法完全理解这个页面上的大部分帖子,但我想我以前遇到过这个问题,并通过允许页面在第一次点击按钮时发布来解决它,所以当页面从服务器返回它具有分配给它的新值,它看起来可点击并启用。 但是如果第二次尝试按下它,那么它就会被禁用,页面将不会发布,并通过单击此按钮再次发送到服务器。 我希望这有帮助:
@section scripts
{
<script type="text/javascript">
$('#edit').click(function () {
if (document.getElementById("edit").value == '') {
// This portion should execute onlythe
// first time button is clicked, and it
// will assign a new value to the button,
//and posts the value
//to the server
}
else {
edit.disabled = true;
}
});
</script>
}
一种简单得多的方法是将用于禁用按钮的任何代码包含在具有 0 延迟的setTimeout()
。 这样,按钮在处理表单提交的线程中仍处于启用状态,同时生成另一个并行线程来进行禁用。
示例(使用 jQuery):
<form method="POST" onsubmit="javascript:setTimeout(() => $('*[type=submit]', this).attr('disabled', 'disabled'), 0)">
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.