验证同一分部视图的多个实例

本文关键字:视图 实例 一分 验证 | 更新日期: 2023-09-27 17:57:02

我有一个场景,我想向用户显示数据并允许他们能够修改它。为此,我有一个预设了当前对象值的表单。此窗体作为分部视图包含在内,该分部视图又在循环中调用,具体取决于我的父对象具有的子对象数。

我还在最后提供了一个空表单,以允许用户创建此子项的新实例,因此简而言之,我有如下所示的内容:

编辑表单(部分视图):

@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的属性,但无济于事。

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

谢谢!

验证同一分部视图的多个实例

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

  1. 编辑器模板或
  2. 传入HtmlFieldPrefix到分部视图 有关更多详细信息,请参阅此博客

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

AddressModel.cshtml (Editor template)

@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)
    {
    }

生成的网页

请注意,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>

我最终设法让它工作。在遇到之前的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