ASP.NET MVC - 使用 jQuery 不显眼的验证防止提交无效表单

ASP.NET MVC - prevent submit of invalid form using jQuery unobtrusive validation

我有一个 ASP.NET 项目,它使用 ASP.NET 构建的 jQuery.Validate and the unobtrusive wrapper 自动连接客户端验证。

a) 我绝对有合适的库:jquery.js, jquery.validate.js, & jquery.validate.unobtrusive.js

b) 并且 MVC 渲染引擎肯定是打开的(ClientValidationEnabled & UnobtrusiveJavaScriptEnabled 在 web.config 的 appSettings 部分)

这里有一个简单的例子,其中有问题:

型号:

public class Person
{
    [Required]
    public string Name { get; set; }
}

控制器:

public ActionResult Edit()
{
    Person p = new Person();
    return View(p);
}

查看:

@model validation.Models.Person

@using (Html.BeginForm()) {
    @Html.ValidationSummary(false)

    @Html.LabelFor(model => model.Name)
    @Html.EditorFor(model => model.Name)
}

这会生成以下客户端标记:

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.15.1/jquery.validate.js"></script>
<script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/mvc/3.0/jquery.validate.unobtrusive.js"></script>
    
<form action="/Person" method="post">
  <div class="validation-summary-valid" data-valmsg-summary="true">
    <ul><li style="display:none"></li></ul>
  </div>
  <label for="Name">Name</label>
  <input data-val="true" data-val-required="The Name field is required." id="Name" name="Name" type="text" value="" />
  <input type="submit" value="Save" />
</form>

当运行时,它将执行客户端验证,注意到某些表单元素无效,然后 post返回服务器。

为什么它不能阻止 post返回状态无效的表单?

问题

当您没有为给定的表单元素包含 @Html.ValidationMessageFor 占位符时,就会发生这种情况。

下面是对问题发生位置的更深入探讨:

提交表单时,jquery.validate.js 将调用以下方法:

validate: function( options ) {
  form: function() {
    showErrors: function(errors) {
      defaultShowErrors: function() {
        showLabel: function(element, message) {
          this.settings.errorPlacement(label, $(element) )

其中errorPlacement会在jquery.validate.unobtrusive.js调用这个方法:

function onError(error, inputElement) { 
   var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
       replace = $.parseJSON(container.attr("data-valmsg-replace")) !== false;

当我们不为验证消息添加占位符时,$(this).find(...) 将找不到任何内容。

意思是container.attr("data-valmsg-replace")会returnundefined

当我们尝试对未定义的值调用 $.parseJSON 时,就会出现问题。如果抛出错误(但未被捕获),JavaScript 将停滞不前,永远不会到达原始方法 (return false) 中阻止表单提交的最后一行代码。

解决方案

升级jQuery验证不显眼

Newer versions of jQuery Validate 更好地处理这个问题并在将它们传递给 $.parseJSON

之前检查空值
function onError(error, inputElement) {  // 'this' is the form element
    var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
        replaceAttrValue = container.attr("data-valmsg-replace"),
        replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;

添加 ValidationMessageFor

要解决核心问题,请确保在表单中输入的每个内容包括:

@Html.ValidationMessageFor(model => model.Name)

这将呈现以下客户端标记

<span class="field-validation-valid" data-valmsg-for="Name" data-valmsg-replace="true"></span>

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.15.1/jquery.validate.js"></script>
<script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/mvc/3.0/jquery.validate.unobtrusive.js"></script>
    
<form action="/Person" method="post">
  <div class="validation-summary-valid" data-valmsg-summary="true">
    <ul><li style="display:none"></li></ul>
  </div>
  <label for="Name">Name</label>
  <input data-val="true" data-val-required="The Name field is required." id="Name" name="Name" type="text" value="" />
  <span class="field-validation-valid" data-valmsg-for="Name" data-valmsg-replace="true"></span>
  <input type="submit" value="Save" />
</form>