使用jQuery防止表单重复提交

5
我使用jquery的.submit()拦截用户的提交事件,但我发现了一个问题。
当用户单击提交按钮时,表单会正常提交,但是如果用户故意快速点击多次,它将会多次提交,这会导致数据库中出现重复数据。
这种问题的解决方案是什么?
更新:我看到有些建议是禁用提交按钮。这可以防止表单被多次提交,但问题是我的页面中的表单元素没有刷新,如果我禁用它,用户将无法再次提交,禁用15秒可能有效,但这是解决这个问题的正确方法吗?

你是用Ajax提交表单吗?如果不是Ajax,禁用表单是个好选择。 - Reigel Gallarde
是的,我正在使用jQuery的load。当用户提交表单时,表格中会增加一行。 - Sawyer
再看一下我的答案,如果有帮助的话... - Reigel Gallarde
1
在页面提交完成后,只需重新启用按钮即可。 - Jerod Venema
5个回答

7
禁用提交按钮确实是正确的做法。
然而,在很多情况下,要执行的服务器端逻辑取决于请求参数映射中所提及的特定提交按钮的名称-值对是否存在。这在基于服务器端组件的MVC框架(如MS ASP.NET和Sun JSF)中尤为常见,但也适用于具有多个提交按钮的“简单”表单。按下的提交按钮的名称-值对是必需的以确定要执行的操作。禁用该按钮会使其名称-值对完全消失在请求参数映射中,服务器端可能不会采取任何操作或执行错误的操作。
基本上有两种方法可以解决这个问题:
  1. Use setTimeout() to disable the button after a few milliseconds so that its name-value pair get sent anyway. 50ms is an affordable amount.

    $("form").submit(function() {
        var form = this;
        setTimeout(function() {
            $(':submit', form).attr('disabled', true);
        }, 50);
    });
    
  2. Copy the name-value pair of the actually pressed submit button into a hidden input of the form. This is a bit trickier since this information isn't available in the submit event of the <form>. You need to let the $(document) capture the last clicked element.

    $("form").submit(function() {
        $(':submit', this).attr('disabled', true);
        $(this).append($('<input/>').attr({
            type: 'hidden',
            name: $.lastClicked.name,
            value: $.lastClicked.value
        }));
    });
    
    $(document).click(function(e) {
        e = e || event;
        $.lastClicked = e.target || e.srcElement;
    });
    

更新:根据您的更新:

好的,我看到有些建议是禁用提交按钮。这可以防止重复提交,但问题是我的页面中的表单元素没有刷新,如果我禁用它,用户将无法再次提交它,禁用它15秒可能有效,但这是解决这个问题的正确方法吗?

所以你实际上正在触发一个ajax请求。在jQuery的ajax函数的回调处理程序中,您可以重新启用按钮。假设您正在使用jQuery.post

$("form").submit(function() {
    // Disable buttons here whatever way you want.

    var form = this;
    $.post('some/url', function(data) {
        // Re-enable buttons at end of the callback handler.
        $(':submit', form).attr('disabled', false);
    });
});

2

抱歉,我在中国,Blogspot被封锁了。政府太邪恶了,哈哈。 - Sawyer

1
尝试在表单提交时禁用提交按钮...
$("form").submit(function() {
    $(':submit',this).attr('disabled','disabled');
    $('selector').load(url,function(){
       $(':submit',this).removeAttr('disabled');
    })
});​

快速演示


什么是“URL”?另外,不要忘记按下回车键提交表单。 - nickf
@nickf - 你也想问我 $('selector') 是什么吗?... OP 没有提供太多代码(只有 .submit())... 所以我假设... 如果文本框处于焦点状态并按下回车键,则会提交,但这还取决于 OP 的代码... - Reigel Gallarde

0

试试这个:

$("form").submit(function() {
    var form = this;
    setTimeout(function() {
        $(':submit', form).attr('disabled', true);
    }, 50);

    setTimeout(function() {
        $(':submit', form).removeAttr('disabled');
    }, 1000);
});

0

真正的问题在于数据库层,必须设计防止重复的机制。以下是一个通用但有点丑陋的解决方案:

当您最初呈现页面时,可以创建一个GUID,比如操作ID,并将其放入视图状态中。当您在服务器端处理事件时,只需将此GUID插入到表中,例如OngoingOperations,其中它是主键。第一次插入将成功,其他插入将失败。当然,为了更加用户友好,您可以跳过后续操作并返回第一个操作的状态。

OngoingOperations表可能如下所示:

CREATE TABLE OngoingOperations( OperationID uniqueidentifier primary key, OperationDate datetime default getdate(), OperationStatus nvarchar(max) );

OperationStatus - 是状态消息或任何要从后续提交返回给客户端的数据。在这里,您可以使用标志(ok或not)或详细消息-根据您的意愿。

此表需要收集旧记录,例如每小时删除2个或更多小时前完成的操作。

Anton Burtsev


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接