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



在一个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设置调用并没有真正关闭异步。如果我把它移出点击功能,它会,但它会禁用所有的异步。相反,页面会立即发出"true"警报,并通过在远程验证操作方法上设置一个断点进行测试。

任何想法?

额外注意:

我忘了说,在IE8中,只有当有问题的文本框没有通过客户端验证时才会触发提交事件。例如,如果它没有通过required或regex,则会触发submit()。对于远程验证操作方法,它不会被触发。但是,一旦客户端验证失败,后续的远程验证也会触发IE8提交事件。

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

以下是视图模型中的相关代码:
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")
}

我也使用防伪令牌,如果这有区别的话。谢谢。

这有点俗套,但我建议您尝试以下方法:

首先,用display="none"隐藏提交按钮,并显示你自己的"提交"按钮,它运行上面的脚本。

其次,在您的页面中,添加一个标志var [var remotePending = false;]和一个变量用于setInterval调用[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
}

这将允许您等待挂起的远程验证完成,然后正常进行。我还没有测试过,所以你可能要玩周围的工作,因为你想要的

我有点晚了,但是我在试图解决类似问题时偶然发现了这个问题。我也不想使用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,但你可以很容易地扩展它来启用/禁用按钮,等等

昨晚我发现自己对这个问题感到困惑,在尝试了各种方法之后,我最终找到了一个进化的辅导员。由于咨询师们并不是直接开箱工作,我想我应该分享一下,以防止其他人也有同样的头痛。这并不是我想要的"干净"的解决方案(我真的很讨厌使用间隔)。但这似乎已经足够了。

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();

我最终解决了这个问题,但是按钮禁用/等待图像显示只发生在有一个有效的提交表单时。不过没关系,因为多个无效表单提交是幂等的,用户可以想点击多少就点击多少。(另外,远程验证操作方法是根据其参数值缓存的。)

$(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);
    });
});

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

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

我检查html生成丢失data-val-remote-additionalfields =".Email"例:我正在检查它们。

最新更新