如果在Ajax表单中使用,jQuery不显眼的验证会忽略提交按钮上的“取消”类

时间:2012-07-19 13:04:21

标签: jquery jquery-validate asp.net-mvc-4 unobtrusive-validation unobtrusive-ajax

我正在尝试使用

实现可选的客户端验证
  • ASP.NET MVC 4,
  • 不引人注目的jQuery验证,
  • unobtrusive ajax

这很好用

以下图片展示了我对可选客户端验证的意思: 我的表单上唯一一个字段应该包含电子邮件,因此附加了一个电子邮件验证程序。

enter image description here

现在我们点击保存。由于我们的文本“name @ doamin”不是有效的电子邮件,因此会显示验证摘要。与验证摘要一起,我们取消隐藏“仍然保存”按钮。

enter image description here

第二个按钮是一个普通的提交按钮,只有class="cancel"。这指示jQuery.validate.js脚本在使用此按钮提交时跳过验证。

以下是视图的代码段:

@using (Html.BeginForm())
{
    <div>
        <input data-val="true" data-val-email="Uups!" name="emailfield" />
        <span class="field-validation-valid" data-valmsg-for="emailfield" data-valmsg-replace="false">*</span>
    </div>

    <input type="submit" value="Save" />
    @Html.ValidationSummary(false, "Still errors:")
    <div class="validation-summary-valid" data-valmsg-summary="true">
        <input type="submit" value="Save anyway" class="cancel" />
    </div>
}

这些都很好。

问题

如果切换到Ajax表单,第二个提交按钮 - “仍然保存”会停止按预期工作。它的行为与正常行为相同,并且在验证成功之前阻止提交。

以下是“ajaxified”视图的代码段:

@using (Ajax.BeginForm("Edit", new { id = "0" },
        new AjaxOptions
            {
                HttpMethod = "POST",
                InsertionMode = InsertionMode.Replace,
                UpdateTargetId = "ajaxSection",
            }))
{
    <div>
        <input data-val="true" data-val-email="Uups!" name="emailfield" />
        <span class="field-validation-valid" data-valmsg-for="emailfield" data-valmsg-replace="false">*</span>
    </div>

    <input type="submit" value="Save" />
    @Html.ValidationSummary(false, "Still errors:")
    <div class="validation-summary-valid" data-valmsg-summary="true">
        <input type="submit" value="Save anyway" class="cancel" name="saveAnyway" />
    </div>
}

我已调试jQuery.validation.js以找出有什么不同,但失败了。

Qustion

欢迎修改或解决问题并让ajax表单符合预期的任何想法。


附录

要有客户端验证是绝对必须的。服务器端验证不是一个选项。除了更高的流量(此示例是简化 - 真实表单包含更多字段)和延迟之外,服务器端验证还有一件事情不会做:客户端验证器突出显示丢失焦点上的错误字段。这意味着只要您切换到下一个字段,就会收到反馈。

3 个答案:

答案 0 :(得分:11)

这是微软不引人注目的ajax脚本的一个已知限制。你可以修改它来修复bug。因此,在jquery.unobtrusive-ajax.js脚本中替换第144行的以下内容:

$(form).data(data_click, name ? [{ name: name, value: evt.target.value }] : []);

使用:

$(form).data(data_click, name ? [{ name: name, value: evt.target.value, className: evt.target.className }] : []);

此外,我们将类名传递给处理程序,以便它可以决定是否应该触发客户端验证。目前,无论点击哪个按钮,它始终会触发验证。现在在第154行,我们修改了以下测试:

if (!validate(this)) {

使用:

if (clickInfo[0].className != 'cancel' && !validate(this)) {

如果使用带有类名取消的提交按钮来提交表单,则不再触发客户端验证。另一种可能性是抓取jquery.unobtrusive-ajax.js脚本并用标准Ajax.BeginForm替换Html.BeginForm,使用普通的旧jQuery可以不引人注意地使用AJAXify。

答案 1 :(得分:6)

最后我找到了一个本身不引人注目的解决方案

    // restore behavior of .cancel from jquery validate to allow submit button 
    // to automatically bypass all jquery validation
    $(document).on('click', 'input[type=image].cancel,input[type=submit].cancel', function (evt)
    {
        // find parent form, cancel validation and submit it
        // cancelSubmit just prevents jQuery validation from kicking in
        $(this).closest('form').validate().cancelSubmit = true;
        $(this).closest('form').submit();
        return false;
    });

注意:如果首先尝试它似乎不起作用 - 请确保您没有往返服务器并刷新页面时出错。您必须通过其他方式绕过服务器端的验证 - 这只是允许提交表单,而不必将.ignore属性添加到表单中的所有内容。

(如果您正在使用按钮,则可能需要将button添加到选择器)

答案 2 :(得分:-1)

如果不需要不显眼的验证,请将其禁用并在服务器端执行所有检查。

您可以检查服务器端的“提交”按钮的值,然后根据该值继续:

为您的两个提交输入添加name属性:

<input type="submit" value="Save" name="btnSubmit" />
<input type="submit" value="Save anyway" class="cancel" name="btnSubmit" />

更新您的行动以string btnSubmit。如果您有模型,可以将其放入模型中。

[HttpPost]
public ActionResult Edit(string emailfield, string btnSubmit)
{
    switch (btnSubmit)
    {
        case "Save":
            if(ModelState.IsValid)
            {
                // Save email
            }
            break;
        case "Save anyway":
            // Save email
            return RedirectToAction("Success");
            break;
    }
    // ModelState is not valid
    // whatever logic to re display the view
    return View(model);
}

<强>更新

我理解客户端验证简化了工作,但是如果你无法弄清楚Ajax有什么问题(我不熟悉它在输入时打字=“取消”时的行为),你可以写一个脚本这将验证服务器端未聚焦的输入:

$('input[type=text]').blur(function(){
    $.ajax({
        url: '/ControllerName/ValidateInput',
        data: { inputName: $(this).val() },
        success: function(data) {
            //if there is a validation error, display it
        },
        error: function(){
            alert('Error');
        }
    });
});

现在您需要创建一个将对输入进行验证的操作:

public ActionResult ValidateInput(string inputName)
{
    bool isValid = true;
    string errorMessage = "";
    switch (inputName)
    {
        case "password"
            // do password validation
            if(!inputIsValid)
            {
                isValid = false;
                errorMessage = "password is invalid";
            }
            break;
        case "email"
            // do email validation
            if(!inputIsValid)
            {
                isValid = false;
                errorMessage = "email is invalid";
            }
            break;
    }
    return Json(new { inputIsValid = isValid, message = errorMessage });
}

这有点麻烦,但正如我所说,如果你不弄清楚客户验证,它可以工作。


<强>更新

不知道为什么我没有想到这个......而不是依靠class="cancel"你可以做这样的事情:

给你的“反正”提交输入ID:

<input type="submit" value="Save anyway" class="cancel" name="btnSubmit" id="submitAyway" />

然后有一个这样的脚本:

$('#submitAyway').click(function(evt) {
    evt.preventDefault();
    $('form').submit();
});

我没有对此进行测试,但从理论上讲,这应该在不验证的情况下提交表单。 您可能仍需要服务器端验证,正如我在第一个示例中所示。