如何让不显眼的jquery远程验证器执行异步..?

时间:2011-10-20 18:44:48

标签: jquery asp.net-mvc-3 jquery-validate unobtrusive-validation remote-validation

在MVC3应用程序中,使用jquery不显眼的验证,以及带有[Remote]验证器的视图/模型:我试图在远程验证期间禁用提交按钮并显示等待图标,并且当提交有效表单时服务器。我以为我已经把它钉在了IE8上。

问题是,当表单无效时,GC和FF没有触发表单的提交事件,因此我在此事件期间禁用了提交按钮。但是,当表单无效时,IE8会触发此事件,导致用户永远无法再次单击它。 (IE8不提交表单,但事件被解雇。)

我尝试将一个函数附加到提交按钮的单击事件。在那里,我禁用了提交按钮,显示了等待图标,并且有:

$('[data-app-form-submit-button="true"]').live('click', function (e) {
    var form = $(this).parents('form');
    var icon = form.find('[data-app-form-submitting-icon="true"]');
    icon.show();
    $(this).attr('disabled', 'disabled');
    $.ajaxSetup({ async: false });
    var isValid = form.valid();
    $.ajaxSetup({ async: true });
    alert(isValid);
});

问题是,ajax设置调用并没有真正关闭异步。如果我将它移出click函数,但它会禁用所有内容的异步。相反,页面立即警告“true”,通过在远程验证操作方法上设置断点进行测试。

有什么想法吗?

附加说明:

我忘了提及,在IE8中,只有在有问题的文本框未能通过客户端进行验证时才会触发提交事件。例如,如果它不需要或正则表达式,则触发submit()。对于远程验证操作方法,不会触发它。但是,一旦客户端验证失败,后续的远程验证也会触发IE8提交事​​件。

对Russ Cam的回应(评论#1)

以下是viewmodel中的相关代码:

public class SignUpForm : IValidatableObject
{
    [DataType(DataType.EmailAddress)]
    [Display(Name = "Email Address")]
    [Required(ErrorMessage = "Email Address is required.")]
    [RegularExpression(@"^(email regex here)$",
        ErrorMessage = "This is not a valid email address.")]
    [Remote("Validate", "ControllerName", "AreaName", HttpMethod = "POST")]
    public string EmailAddress { get; set; }

    public IEnumerable<ValidationResult> Validate(
        ValidationContext validationContext)
    {

我很高兴你让我看看渲染的<form>。表单标记和输入元素如下所示:

<form action="/post-action-method" method="post" novalidate="novalidate">
...
<input class="text-box single-line" data-app-focus="true" data-val="true" 
    data-val-regex="This is not a valid email address." 
    data-val-regex-pattern="^(email regex here)$" 
    data-val-remote="&amp;#39;Email Address&amp;#39; is invalid." 
    data-val-remote-additionalfields="*.EmailAddress" 
    data-val-remote-type="POST" 
    data-val-remote-url="/validate-action-method" 
    data-val-required="Email Address is required." 
    id="EmailAddress" name="EmailAddress" type="text" value=""> 
 ... 
<input type="submit" value="Submit this form" 
    data-app-form-submit-button="true" />

到目前为止,我从未见过novalidate =“novalidate”属性。以下是cshtml文件中的内容:

@using (Html.BeginForm())
{
    @Html.EditorForModel()
    @Html.AntiForgeryToken("assault")
}

我也在使用反伪造令牌,如果这有所不同。感谢。

5 个答案:

答案 0 :(得分:3)

这有点像hacky,但我建议尝试以下方法。

首先,使用display="none"隐藏提交按钮,然后显示您自己的“提交”按钮,该按钮会运行上面的脚本。

其次,在您的页面中,为var remotePending = false;调用[setInterval]添加标记var [var intervalPending;]和变量,并在脚本中将标志设置为true,然后使用intervalPending = setInterval('remoteCheck()', 200);

调用以下函数
function remoteCheck() {
    if ($.validator.pendingRequest == 0) {
        // requests are done
        // clear interval
        clearInterval(intervalPending);
        // re-enable our "submit" button

        // "click" the hidden button
        $("#hiddenSubmit").click();
    }
    // we will try again after the interval passes
}

这将允许您等待挂起的远程验证完成,然后正常进行。我没有测试过,所以你可能需要四处游戏才能让它按照你想要的方式工作。

答案 1 :(得分:2)

我有点迟到了,但在试图解决类似问题时我偶然发现了这个问题。我也不想使用Interval,所以我制定了一个不同的解决方案,并认为这里可能值得为其他人详细说明。

最后我决定覆盖jQuery验证器startRequest和stopRequest方法,以便添加我自己的逻辑。执行我自己的逻辑后,我只需调用旧的验证器方法。

// Extend jQuery validator to show loading gif when making remote requests
var oldStartRequest = $.validator.prototype.startRequest;
$.validator.prototype.startRequest = function (element) {
    var container = $('form').find("[data-valmsg-for='" + element.name + "']");
    container.addClass('loading');       

    oldStartRequest.apply(this, arguments);
};

var oldStopRequest = $.validator.prototype.stopRequest;
$.validator.prototype.stopRequest = function (element) {
    var container = $('form').find("[data-valmsg-for='" + element.name + "']");
    container.removeClass('loading');

    oldStopRequest.apply(this, arguments);
};

我想为我的目的做的只是简单地将'loading'css类添加到相邻的验证消息字段以显示加载gif,但是您可以轻松扩展它以启用/禁用按钮等。< / p>

答案 2 :(得分:1)

昨晚我发现自己很困惑,在尝试了各种方法后,我最终得到了辅导员的演变。由于辅导员没有直接开箱即用,我认为我会分享它以防止其他人同样头痛。它不是我想要的“干净”解决方案(我真的讨厌使用间隔)。但似乎就足够了。

var iIntervalId = null;

//
// DECLARE FUNCTION EXPRESSIONS
//

//==============================================================================
// function that triggers update when remote validation completes successfully
//==============================================================================
var fnPendingValidationComplete = function () {

  var validator = $("#frmProductType").data("validator");
  if (validator.pendingRequest === 0) {

    clearInterval(iIntervalId);

    //Force validation to present to user (this will not retrigger remote validation)
    if ($("#frmProductType").valid()) {

      alert("valid - you can submit now if you like");

    }
    //else { alert("invalid"); }
  }
  //else { alert("NOT YET"); }
},

//==============================================================================
// Trigger validation
//==============================================================================
fnTriggerValidation = function (evt) {

  //Remove any cached values to ensure that remote validation is retriggered
  $("#txtProductType").removeData("previousValue");

  //Trigger validation
  $("#frmProductType").valid();

  //Setup interval which will evaluate validation (this approach because of remote validation)
  iIntervalId = setInterval(fnPendingValidationComplete, 50);
};

fnTriggerValidation();

答案 3 :(得分:0)

我最终解决了这个问题,但只有在有效的提交表单时才会显示按钮禁用/等待图像。没关系,因为多个无效表单提交是幂等的,用户可以根据需要点击。 (此外,远程验证操作方法将根据其参数值进行缓存。)

$(function () {
    $('form').bind('invalid-form.validate', function () {
        $('form').each(function () {
            $(this).find(
                '[data-app-form-submitting-icon="true"]').hide();
            var button = $(this).find(
                'input[type="submit"][data-app-form-submit-button="true"]');
            setTimeout(function () {
                button.removeAttr('disabled');
            }, 1);
        });
    });
    $('form').live('submit', function (e) {
        $(this).find('[data-app-form-submitting-icon="true"]').show();
        var button = $(this).find(
            'input[type="submit"][data-app-form-submit-button="true"]');
        setTimeout(function () {
            button.attr('disabled', 'disabled');
        }, 0);
    });
});

这也有点hacky,但是当我没有使用setTimeout时,提交操作永远不会触发无效的处理程序。

答案 4 :(得分:0)

我尝试了所有方法,一切都很好,但没有任何效果。 然后我检查模型(类或 DTO)项目的 System.Web.Mvc 版本和 View 的项目有版本差异。我将两者都更新为相同的版本,它对我有用。

我检查了 html generate 丢失了 data-val-remote-additionalfields=".Email" 例如,我正在检查它们。