如何在客户端访问模型错误?

时间:2012-02-02 23:32:39

标签: jquery asp.net-mvc-3

我不喜欢内置的Html.ValidationSummary助手,因为我希望在表单顶部显示一条消息,例如......

存在验证错误。无效字段已突出显示。

内置的ValidationSummary根本不输出任何内容或输出所有字段的列表。我只想要一个简洁的信息。

我的表单顶部有一个div,按我想要的方式设置,然后当页面加载时,我将以下方法挂钩到表单上...

function CheckFormForValidationErrors() 
{
    if (!$("form").valid()) 
    {
        $(".validation-notification").css("visibility", "visible");
    }
}

当客户端上存在验证错误时,这非常有用。问题是客户端验证成功但服务器端验证(如登录表单)。如果用户输入正确的用户名和密码,则表单验证成功但登录失败。在服务器端,我正在添加模型错误,如此...

ModelState.AddModelError(string.Empty, "Login failed");

但我无法弄清楚如何在客户端上显示消息。如果你有更好的想法来实现我的目标,那么我愿意废弃我的想法并改变方向。我想做的事情不应该那么难。

2 个答案:

答案 0 :(得分:4)

当您在视图中时,ModelState位于ViewData

 ViewData.ModelState

并收到错误消息:

 foreach(string key in ViewData.ModelState.Keys)
 {
     foreach (var error in ViewData.ModelState[key].Errors)
     {
         string err = error.ErrorMessage;
     }
 }

在Razor中,也许这会起作用(我的剃刀生锈了)

@if (!ViewData.ModelState.IsValid)
{
    <ul>
    @foreach (string key in ViewData.ModelState.Keys)
    {
        @foreach (var error in ViewData.ModelState[key].Errors)
        {
            <li>@error.ErrorMessage</li>
        }
    }
    </ul>
}

答案 1 :(得分:2)

你有很多选择。如果您只想显示由此创建的消息:

ModelState.AddModelError(string.Empty, "Login failed");

您只需在视图中使用此功能:

@Html.ValidationMessage(String.Empty)

然而,这会将消息包装在<span class="field-validation-error"></span>中,但如果您愿意,可以轻松覆盖默认样式。

然而,根据您在上面描述的用例,您需要的只是一个静态(ish)图例,它解释了“有验证错误。无效字段已突出显示。“只要屏幕上有一个或多个验证失败。

那怎么样:

namespace MvcApplication.Web.Extensions
{
    public static class HtmlHelperExtensions
    {
        private const string ValidationLegendHtml = 
            "<div class=\"validation-legend\">{0}</div>";
        private const string DefaultValidationLegend =
            "There are validation errors. The invalid fields have been highlighted";

        public static MvcHtmlString ValidationLegend(
            this HtmlHelper htmlHelper, string message = DefaultValidationLegend)
        {
            if(htmlHelper.ViewData.ModelState.IsValid)
            {
                return null;
            }
            return new MvcHtmlString(String.Format(ValidationLegendHtml, message));
        }
    }
}

然后在视图中您只需要插入:

@Html.ValidationLegend()    //Use the default legend message
@Html.ValidationLegend("Something went wrong!")    //Specific message

如果表单无效,则会显示图例,并在其有效时完全不可见!

您还需要将新扩展名的名称空间添加到 Views /web.config(不要与root web.config混淆),如下所示:

<pages pageBaseType="System.Web.Mvc.WebViewPage">
  <namespaces>
    <add namespace="System.Web.Mvc" />
    <add namespace="System.Web.Mvc.Ajax" />
    <add namespace="System.Web.Mvc.Html" />
    <add namespace="System.Web.Routing" />

    <!-- Add Me! -->
    <add namespace="MvcApplication.Web.Extensions"/>
  </namespaces>
</pages>

不幸的是,这不会为您提供新扩展方法的智能感知,如果这很重要,您可以选择(或另外)在@model声明后立即将扩展的using语句添加到视图顶部像这样:

@model MvcApplication.Web.Models.LoginModel
@using MvcApplication.Web.Extensions

修改

如果您想支持显示此客户端,请将扩展名更改为:

public static MvcHtmlString ValidationLegend(
    this HtmlHelper htmlHelper, string message = DefaultValidationLegend)
{
    var tagBuilder = new TagBuilder("div");
    tagBuilder.SetInnerText(message);
    tagBuilder.AddCssClass("validation-legend");

    if(htmlHelper.ViewData.ModelState.IsValid)
    {
        tagBuilder.AddCssClass("hide");
    }

    return new MvcHtmlString(tagBuilder.ToString());
}

确保您拥有.hide { display: none; } CSS规则。

再次编辑

您可以通过设置errorContainer配置设置的默认值以匹配图例的CSS类,将其留给jquery.validate自动显示/隐藏图例。这可以通过声明脚本包含如下:

来完成
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")"
        type="text/javascript"></script>
<script type="text/javascript">
    jQuery.validator.setDefaults({ errorContainer: '.validation-legend' });
</script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"
        type="text/javascript"></script>

请注意在 jquery.validate脚本标记之后来的setDefaults调用,但之前 jquery.validate.unobtrusive脚本标记。这个顺序很重要。另请注意,任何验证错误都会显示所有.validation-legends,因此如果您有任何具有两种不同验证图例的屏幕,则可能需要更加花哨。