ASP.NET MVC - 如何使用jquery.validate.unobtrusive lib防止双击提交?

时间:2010-12-27 14:20:21

标签: asp.net-mvc-3 double-submit-prevention unobtrusive

我需要避免双击提交行为。我正在使用不显眼的库进行客户端验证。我有以下代码来避免双重clic:

jQuery.fn.preventDoubleSubmit = function () {
         var alreadySubmitted = false;
         return jQuery(this).submit(function () {

             if (alreadySubmitted)
                 return false;
             else {
                 alreadySubmitted = true;
             }
         });
     };

     jQuery('form').preventDoubleSubmit();

不幸的是,如果我的表单有一些可验证的字段(例如,必填字段),上面的代码仍然被触发,因此,即使我更正了表单上的任何错误,我也无法提交它试。

如何在验证成功完成后触发双击代码?

9 个答案:

答案 0 :(得分:17)

您还可以使用 JQuery One event

我发现通过双击快速,我可以通过双击来避开大多数防守。使用one事件是确保事件仅被触发一次的唯一真实方法。我不认为这种技术可以使用input type = submit标签“开箱即用”。相反,您只需使用输入类型=按钮或 JQueryUI's .button()

$("#submitButton").one("click", function(event) {
   $('#theForm').submit();
});

如果您需要在验证错误(或其他情况)下重新连接事件,我建议您为事件处理程序创建一个函数。此示例中不需要该函数,因为所有事件处理程序都提交表单,但在更复杂的情况下,您可能希望避免重复自己。

function submitClick(event) {
   $('#theForm').submit();
}

$("#submitButton").one('click', function(event) {
   submitClick(event);
});

// This handler will re-wire the event when the form is invalid.
$('#theForm').submit(function(event) {
   if (!$(this).valid()) {
      event.preventDefault();
      $('#submitButton').one('click', function(event) { submitClick(event); });
   }
});

如果您想向用户反馈该按钮不再起作用,您可以在此处添加禁用代码。使用One事件的一个很好的副作用是你实际上不必禁用按钮,你可以使用自己的风格。

function submitClick(event) {
   $('#submitButton').addClass('disabledButton');
   $('#theForm').submit();
}

$("#submitButton").one('click', function(event) {
   submitClick(event);
});

// This handler will re-wire the event when the form is invalid.
$('#theForm').submit(function(event) {
   if (!$(this).valid()) {
      event.preventDefault();
      $('#submitButton').one('click', function(event) { submitClick(event); });
      $('#submitButton').removeClass('disabledButton');
   }
});

JQuery One Event: http://api.jquery.com/one/

答案 1 :(得分:8)

我用以下代码解决了它:

var tryNumber = 0;
 jQuery('input[type=submit]').click(function (event) {
     var self = $(this);

     if (self.closest('form').valid()) {
         if (tryNumber > 0) {
             tryNumber++;
             alert('Your form has been already submited. wait please');
             return false;
         }
         else {
             tryNumber++;
         }
     };
 });

注意:您也可以替换:

return false;

行,用于:

self.attr('disabled', true);

但是,如果您使用控制器上的提交按钮的名称来获取额外的逻辑,它们将被发送为null。 (您可以在提交前使用额外的隐藏字段来收费)

就是这样,希望它有所帮助

罗德里戈

编辑:感谢这些帖子: jquery newbie: combine validate with hidding submit button

答案 2 :(得分:3)

为什么不使用:

function disableButtons() {
    var form = $(this);
    var btns = $("input:submit", form);

    if (!form.valid()) {
        // allow user to correct validation errors and re-submit
        btns.removeAttr("disabled");
    } else {
        btns.attr("disabled", "disabled");
    }
}

禁用按钮并使用以下命令激活它:

$("form").bind("submit", disableButtons);

答案 3 :(得分:3)

基于Ryan P's popular answer,我创建了以下通用解决方案,该解决方案也适用于我的ajax表单。

使用以下类装饰您的自定义提交按钮:

<button type="button" class="one-click-submit-button">Submit</button>

将以下内容添加到您的javascript文件中:

function OneClickSubmitButton() {
    $('.one-click-submit-button').each(function () {
        var $theButton = $(this);
        var $theForm = $theButton.closest('form');

        //hide the button and submit the form
        function tieButtonToForm() {
            $theButton.one('click', function () {
                $theButton.hide();
                $theForm.submit();
            });
        }

        tieButtonToForm();

        // This handler will re-wire the event when the form is invalid.
        $theForm.submit(function (event) {
            if (!$(this).valid()) {
                $theButton.show();
                event.preventDefault();
                tieButtonToForm();
            }
        });
    });
}

OneClickSubmitButton();

因为这是一个ajax形式,所以如果我们的服务器验证失败,我们想重新加载处理程序。

function MyForm_OnSuccess() {
    if (true if your form passed validation logic) {
        //do something since your form submitted successfully
    } else { //validation failed on server
        OneClickSubmitButton(); //reinitialize the button logic
    }
}

显然,如果您没有ajax表单,则可以省略整个OneClickSubmitButton函数业务并直接运行$('.one-click-submit-button').each(...

答案 4 :(得分:2)

 $('form').submit(function () {
 $('input[type="submit"]', this).attr('disabled', 'disabled');
   });

答案 5 :(得分:1)

我有一个使用MVC3不显眼验证的表单,以及一个带有[RemoteAttribute]的viewmodel。 它看起来像表单的提交事件只有在所有验证通过后才会触发。我目前正在使用它,它似乎有效:

<input type="submit" value="Submit the Form" 
    data-app-disable-on-submit="true" />

$('form').live('submit', function() {
    $(this).find('input[type="submit"][data-app-disable-on-submit="true"]')
                .attr('disabled', 'disabled');
})

我在远程属性验证操作方法和HttpPost操作方法上都设置了断点。单击提交按钮,第一次点击验证操作方法上的断点。此时,该按钮仍处于启用状态。我可以多次单击它,并在恢复验证方法后,HttpPost只被命中一次。点击HttpPost时,提交按钮被禁用。

<强>更新

你是亚历克斯。所以上面的更新版本看起来像这样:

$('form').on('submit', function() {
    $(this).find('input[type="submit"][data-app-disable-on-submit="true"]')
                .attr('disabled', 'disabled');
})

答案 6 :(得分:1)

我使用不同的方法。没有连接到按钮的click事件,而是连接到表单的submit事件。像一个魅力,以防止多个同时提交表格。

function initFormsToPreventSimultaneousSubmits(selector) {
    if (!selector) {
        selector = 'form'; // No selector supplied, apply to all forms on the page
    }

    // Make sure all forms that conform to selector are marked as not submitting
    $(selector).each(function()
    {
        var $form = $(this);
        $form.data('submitting', false);
    });

    // Attach to submit event of all forms that conform to selector
    $(selector).off('submit').on('submit', function (e) {
        var $form = $(this);

        if (!$form.valid || $form.valid()) { // Make sure to only process when the form is valid or jquery validation is not used
            if ($form.data('submitting')) {
                // form is already submitting. Classic case of double click on one of the submit buttons of the form. Stop the submit
                e.preventDefault();
                return false;
            } else {
                // All ok, mark the form as submitting and let the form perform the submit
                $form.data('submitting', true);
                return true;
            }
        }
    });
}

在文档就绪时,我调用initFormsToPreventSimultaneousSubmits()来初始化页面上的所有表单。

唯一需要记住的是,当你使用ajax表单时,就是在AjaxOptions设置的OnComplete事件上调用initFormsToPreventSimultaneousSubmits('#formId')。因为否则表格在完成后仍会被标记为提交。当使用“普通”表格帖子时,这不是问题。

答案 7 :(得分:0)

AlexRyan P的答案扩展到帐户,以解决jQuery验证可能缺失的情况以及单个表单中存在多个提交按钮的情况。

oneClickSubmitButton = function () {
    $('input[type=submit], button[type=submit], input[type=image]').each(function () {
        var $theButton = $(this);
        var $theForm = $theButton.closest('form');

        //hide the button and submit the form
        function tieButtonToForm() {
            $theButton.one('click', function () {
                $theButton.addClass('ui-state-disabled');
            });
        }

        tieButtonToForm();

        $theForm.submit(function (event) {
            // Only proceed for the clicked button
            if (!$theButton.hasClass("ui-state-disabled"))
                return;

            // If jQuery Validation is not present or the form is valid, the form is valid
            if (!$theForm.valid || $theForm.valid())
                return;

            // Re-wire the event
            $theButton.removeClass('ui-state-disabled');
            event.preventDefault();
            tieButtonToForm();
        });
    });
};

答案 8 :(得分:0)

我能用几行代码解决类似的问题。如果您不想“警告”用户他们双击并且只是默默地忽略第二次点击,我更喜欢这个。

我刚刚创建了一个全局javascript变量,当我的函数在一个关键部分执行时,我切换了该变量。这使得后续函数调用重新执行相同的部分。

for (int i = 0; i < cbAvailableEntities.Items.Count - 1; i++) {
SqlConnection connection = new SqlConnection(connString);
SqlCommand com = new SqlCommand("InsertProjectEntity", connection);
SqlCommand dcm = new SqlCommand();

using(connection) {
    //First time going through the loop, i = 0 is true.
    if (i == 0) {
        connection.Open();
        using(com) {
            //This will remove anything in the DB related to the ProjectID being edited.
            dcm.Connection = connection;
            dcm.CommandText = "DELETE FROM [dbo].[ProjectEntity] WHERE ProjectID = " + _pID;
            dcm.ExecuteNonQuery();
            //This will insert all items checked in the checkboxlist but will not insert the unchecked.
            if (cbAvailableEntities.Items[i].Selected) {
                com.CommandType = CommandType.StoredProcedure;
                SqlParameter paramPID = new SqlParameter("@ProjectID", nr.ProjectID);
                com.Parameters.Add(paramPID);
                nr.Entities = cbAvailableEntities.Items[i].Value;
                com.Parameters.AddWithValue("@CorpID", nr.Entities);
                com.ExecuteNonQuery();
            }

        }
    } else {
        connection.Open();
        using(com) {
            //This will insert all items checked in the checkboxlist but will not insert the unchecked.
            if (cbAvailableEntities.Items[i].Selected) {
                com.CommandType = CommandType.StoredProcedure;
                SqlParameter paramPID = new SqlParameter("@ProjectID", nr.ProjectID);
                com.Parameters.Add(paramPID);
                nr.Entities = cbAvailableEntities.Items[i].Value;
                com.Parameters.AddWithValue("@CorpID", nr.Entities);
                com.ExecuteNonQuery();
            }
        }
    }
}