验证同一分部视图的多个实例
本文关键字:视图 实例 一分 验证 | 更新日期: 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。
为了解决这个问题,我覆盖了ID
和Name
的属性,但无济于事。
从本质上讲,我只希望错误消息显示在适当的表单旁边。我对这种方法相当绿色,所以如果不正确,请告诉我。我的目标是允许用户在特定屏幕上查看/编辑和创建数据。
谢谢!
不要自己生成name
和id
属性的值。MVC 可以做到这一点,如果你使用:
- 编辑器模板或
- 传入
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)
{
}
生成的网页
请注意,name
和 id
属性具有唯一的数值索引,在此示例中为 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