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

5
我不喜欢内置的Html.ValidationSummary帮助程序,因为我想在表单顶部只显示一个消息,例如...
“存在验证错误。无效字段已被突出显示。”
内置的ValidationSummary要么根本不输出任何东西,要么输出所有字段的列表。我只想要一个简明扼要的消息。
我在表单顶部有一个我想要的样式化div,当页面加载时,我将以下方法挂接到表单上...
function CheckFormForValidationErrors() 
{
    if (!$("form").valid()) 
    {
        $(".validation-notification").css("visibility", "visible");
    }
}

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

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

但是我不知道如何在客户端上显示消息。如果您有更好的想法来实现我的目标,那么我愿意放弃我的想法并改变方向。我试图做的事情并不应该很难。

2个回答

7
当你在自己的视图中时,ModelState 存储在 ViewData 中。
 ViewData.ModelState

获取错误信息的方法:

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

在Razor中,也许这样可以工作(我的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>
}

3

您有许多选项。如果您只想显示创建的消息,则可以使用以下方法:

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

您只需要在视图中添加以下内容:

您只需要在视图中添加以下内容:

@Html.ValidationMessage(String.Empty)

这将会把信息包裹在一个<span class="field-validation-error"></span>中,但如果你愿意的话,这个默认样式可以很容易地被覆盖。
然而,根据你上述所描述的使用情况,看起来你需要的只是一个静态(或类静态)图例,解释“存在验证错误。无效字段已被突出显示。”每当屏幕上有一个或多个验证失败时。
那么怎么样呢:
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 中(不要与根 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声明后立即添加一个使用语句将扩展引入到视图中:

@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规则。
再次编辑:
您可以将显示/隐藏图例交给jquery.validate自动处理,方法是将errorContainer配置设置的默认值设置为与legend的CSS类匹配。可以通过以下方式声明脚本包含:
<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脚本标签之后但在jquery.validate.unobtrusive脚本标签之前调用setDefaults方法。这个顺序很重要。还要注意,任何验证错误都会显示所有的.validation-legends,所以如果您有任何屏幕有两个不同的validation-legends,您可能需要更加精细。


我尝试了您的示例,它很好用,但客户端验证无法正常工作。如果我输入无效值,字段会变成红色,但顶部没有消息。如果我使用无效凭据尝试登录,则会显示出来。我正在尝试让消息在客户端验证错误和服务器端验证错误都能够显示出来。 - oliwa
抱歉,你修改了你的答案,我在改变我的评论之前没有看到它。我会尝试你的建议,但我觉得你找到了我所缺少的连接。 - oliwa
1
请查看我的更新答案,它还可以在客户端错误时自动为您显示/隐藏图例! - Dan Turner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接