【问题标题】:Validating multiple instances of same partial view验证同一局部视图的多个实例
【发布时间】:2014-04-07 11:35:49
【问题描述】:

我有一个场景,我想向用户显示数据并允许他们修改它。为此,我有一个预置了当前对象值的表单。此表单包含在部分视图中,该部分视图又根据我的父对象有多少子对象在循环中调用。

我还在末尾提供了一个空表单,以允许用户创建此子项的新实例,所以简而言之,我有这样的内容:

编辑表单(部分视图):

@model WebPortal.Models.AddressModel

@using (Html.BeginForm("EditAddress", "MerchantDetailsEditor", FormMethod.Post))
{
    @Html.ValidationSummary(true)

    @Html.LabelFor(model => model.StreetNumber, new { id = Model.ID + "_streetnumber_label", Name = Model.ID + "_streetnumber_label", @for = Model.ID + "_streetnumber" })
    @Html.TextBoxFor(address => address.StreetNumber, new { id = Model.ID + "_streetnumber", Name = Model.ID + "_streetnumber"})
    @Html.ValidationMessageFor(address => address.StreetNumber)

创建表单(另一个局部视图)

@model WebPortal.Models.AddressModel
@{
    int counter = 1;
}

@using (Html.BeginForm("AddAddress", "MerchantDetailsEditor", FormMethod.Post))
{
    @Html.ValidationSummary(true)

    @Html.LabelFor(model => model.StreetNumber, new { id = counter + "_streetnumber_label", Name = counter + "_streetnumber_label", @for = counter + "_streetnumber" })
    @Html.TextBoxFor(address => address.StreetNumber, new { id = counter + "_streetnumber", Name = counter + "_streetnumber"})
    @Html.ValidationMessageFor(address => address.StreetNumber)
    counter++;

依次调用如下:

@foreach (WebPortal.Models.AddressModel address in @Model.Addresses)
{
    @Html.Partial("Edit_Form", address)
}
@Html.Partial("Add_Form", new WebPortal.Models.AddressModel())

我面临的问题是,由于它们都共享相同的模型,因此验证错误将被应用并显示在我显示的所有实例旁边。所以如果我在哪里编辑一个对象,我会得到错误,因为另一个表单(添加表单)是空的。

我已经读到这是因为 MVC 在视图级别应用组件ID,所以由于我使用同一视图的多个实例,它们都获得相同的 ID。

为了解决这个问题,我覆盖了 IDName 的属性,但无济于事。

本质上,我只是希望将错误消息显示在适当的表单旁边。我对这种方法相当陌生,所以如果它不正确,请告诉我。我的目标是允许用户在特定屏幕上查看/编辑和创建数据。

谢谢!

【问题讨论】:

    标签: c# asp.net-mvc asp.net-mvc-4 razor


    【解决方案1】:

    不要自己生成nameid 属性的值。如果你使用 MVC 可以做到这一点:

    1. 编辑器模板或
    2. HtmlFieldPrefix 传递到您的部分视图See this blog for more details

    我要向您展示的解决方案是编辑器模板。

    AddressModel.cshtml(编辑器模板)

    @model WebPortal.Models.AddressModel
    
    @Html.LabelFor(model => model.StreetNumber)
    @Html.TextBoxFor(address => address.StreetNumber)
    @Html.ValidationMessageFor(address => address.StreetNumber)
    

    查看

    @for (int i = 0; i < Model.Addresses.Count; i++)
    {
        using (Html.BeginForm("EditAddress", "MerchantDetailsEditor"))
        {
            @Html.ValidationSummary(true)    
            <input type="hidden" name="Addresses.Index" value="@i" /> //http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/
            @Html.EditorFor(m => m.Addresses[i]) //uses AddressModel.cshtml
            <input type="submit" value="Edit" />
        }
    }
    
    @using (Html.BeginForm("AddAddress", "MerchantDetailsEditor"))
    {
        @Html.ValidationSummary(true)
        @Html.EditorFor(m => m.AddAddress)
        <input type="submit" value="Add" />
    }
    

    控制器

        [HttpPost]
        public ActionResult EditAddress([Bind(Prefix="Addresses")] AddressModel[] i)
        {
             //learn more about BindAttribute here
             http://stackoverflow.com/questions/1317523/how-to-use-bind-prefix
        }
    
        [HttpPost]
        public ActionResult AddAddress([Bind(Prefix = "AddAddress")] AddressModel i)
        {
    
        }
    

    生成的 HTML

    请注意,nameid 属性具有唯一的数字索引,在此示例中为 0

    <form action="/Home/EditAddress" method="post">
      <input type="hidden" name="Addresses.Index" value="0" />
      <label for="Addresses_0__StreetNumber">Street Number</label>
      <input data-val="true" data-val-required="The Street Number field is required." id="Addresses_0__StreetNumber" name="Addresses[0].StreetNumber" type="text" value="" />
      <span class="field-validation-valid" data-valmsg-for="Addresses[0].StreetNumber" data-valmsg-replace="true"></span>
      <input type="submit" value="Edit" />
    </form>
    

    【讨论】:

    • 我无法测试您的方法,因为我已经解决了大部分问题。话虽如此,我认为将您的答案留在这里是一个好主意,以便对将来遇到此问题的任何人有所帮助。
    【解决方案2】:

    我最终设法让这个工作。在遇到 this 之前的 SO 问题后,我选择使用 Actions 代替。所以代码现在看起来像这样:

    编辑表单(仍然是部分视图)

    @model WebPortal.Models.AddressModel
    
    
    @using (Html.BeginForm("EditAddress", "MerchantDetailsEditor", FormMethod.Post))
    {
        @Html.ValidationSummary(true)
    
        @Html.HiddenFor(model => model.ID)
    
        @Html.LabelFor(model => model.StreetNumber, new { id = Model.ID + "_streetnumber_label" })
        @Html.TextBoxFor(address => address.StreetNumber, new { id = Model.ID + "_streetnumber" })
        @Html.ValidationMessageFor(address => address.StreetNumber)
     ...
    

    创建表单(仍然是局部视图)

    @model WebPortal.Models.AddressModel
    @{
        int counter = 1;
    }
    
    @using (Html.BeginForm("AddAddress", "MerchantDetailsEditor", FormMethod.Post))
    {
        @Html.ValidationSummary(true)
    
        @Html.LabelFor(model => model.StreetNumber, new { id = counter + "_streetnumber_label" })
        @Html.TextBoxFor(address => address.StreetNumber, new { id = counter + "_streetnumber"})
        @Html.ValidationMessageFor(address => address.StreetNumber)
     ...
    

    主要的变化是我接下来所做的:

    <h2>Addresses</h2>
    @foreach (WebPortal.Models.AddressModel address in @Model.Addresses)
    {
        @Html.Action("_AddressEdit", address)
    }
    
    @if (ViewBag.AddressToAdd != null)
    {
        @Html.Action("_AddressAdd", (WebPortal.Models.AddressModel)ViewBag.AddressToAdd)
    }
    else
    {
        @Html.Action("_AddressAddNew")
    }
    

    我基本上为我的局部视图的每个实例提供了一个动作。这让我可以绕过答案中链接中暴露的问题。

    我的控制器现在看起来像这样:

     #region Actions
        public ActionResult _AddressEdit(AddressModel addressModel)
        {
            return View("...", addressModel);
        }
    
        public ActionResult _AddressAdd(AddressModel addressModel)
        {
            return View("...", addressModel);
        }
    
        public ActionResult _AddressAddNew()
        {
            return View("...");
        }
        #endregion Actions
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-13
      • 1970-01-01
      相关资源
      最近更新 更多