当在 MVC 5 中使用 ajax.actionlink 动态调用同一局部视图的多个实例时,模型绑定不起作用
Model binding doesn't work when multiple instances of the same partial view are called dynamically with ajax.actionlink in MVC 5
我正在构建一个餐厅预订系统。当用户创建预订时,他们还可以决定将在预订中使用哪些家具。为此,我创建了一个局部视图,因此每次用户单击 "add furniture" 时,局部视图都会加载 ajax,然后用户可以在其中指定家具的种类和数量。他们可以根据需要添加任意数量的家具,这意味着他们可以根据需要多次调用分部视图。我的问题来自模型绑定器,然后模型绑定器将所有这些部分视图实例绑定到类型 "BistroReservations_ReservationsFurniture" 的列表对象。请帮助如何使模型活页夹工作。
MainView(请查看底部的 ajax.actionlink 调用 "Add Furniture"
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>BistroReservations_Reservation</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.DateOfArrival, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.DateOfArrival, new { htmlAttributes = new { @class = "form-control datecontrol" } })
@Html.ValidationMessageFor(model => model.DateOfArrival, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.BistroReservations_ShiftID, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("BistroReservations_ShiftID", null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.BistroReservations_ShiftID, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.BistroReservations_GuestID, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-6">
@Html.DropDownList("BistroReservations_GuestID", null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.BistroReservations_GuestID, "", new { @class = "text-danger " })
@Ajax.ActionLink("Create a New Guest", "NewGuest", new AjaxOptions
{
HttpMethod = "GET",
UpdateTargetId = "NewGuest",
InsertionMode = InsertionMode.ReplaceWith,
})
</div>
</div>
<div id="NewGuest" class="form-group">
</div>
<br />
<div class="form-group">
@Html.LabelFor(model => model.ArrivalTime, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("ArrivalTime", null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.ArrivalTime, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.LocationID, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("LocationID", null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.LocationID, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.BistroReservations_TypeOfSeatingID, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("BistroReservations_TypeOfSeatingID", null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.BistroReservations_TypeOfSeatingID, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.TableNoID, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("TableNoID", null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.TableNoID, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.BistroReservations_StatusID, "BistroReservations_StatusID", htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("BistroReservations_StatusID",null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.BistroReservations_StatusID, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Comment, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor( model => model.Comment, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Comment, "", new { @class = "text-danger" })
@Ajax.ActionLink("Add Furniture", "Furniture", new AjaxOptions
{
HttpMethod = "GET",
UpdateTargetId = "Furniture",
InsertionMode = InsertionMode.InsertAfter
})
</div>
</div>
<div id="Furniture" class="form-group">
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
返回家具局部视图的ActionResult
public PartialViewResult Furniture()
{
ViewBag.BistroReservations_FurnitureID = new SelectList(db.BistroReservations_Furnitures, "BistroReservations_FurnitureID", "Description");
return PartialView("_Furniture");
}
家具局部视图
@model CdvPortal.Models.BistroReservations.BistroReservations_ReservationFurniture
<div class="form-horizontal">
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.BistroReservations_FurnitureID, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("BistroReservations_FurnitureID", null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.BistroReservations_FurnitureID, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group ">
@Html.LabelFor(model => model.Quantity, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Quantity, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Quantity, "", new { @class = "text-danger" })
</div>
</div>
</div>
家具模型
public class BistroReservations_ReservationFurniture
{
public int BistroReservations_ReservationFurnitureID { get; set; }
public int BistroReservations_ReservationID { get; set; }
public virtual BistroReservations_Reservation BistroReservations_Reservation { get; set; }
[Display(Name="Furniture Type")]
public int BistroReservations_FurnitureID { get; set; }
public virtual BistroReservations_Furniture BistroReservations_Furniture { get; set; }
public int Quantity { get; set; }
}
您 @Ajax.ActionLink()
方法返回的视图具有重复的 id
属性(无效 html)和重复的 name
属性,这些属性没有正确的前缀 属性 名称并且不包括用于绑定到集合的索引器。例如,如果集合 属性 被命名为 FurnitureItems
,那么 typeof BistroReservations_ReservationFurniture
的 Quantity
属性 所需的 html 需要是
<input type="text" name="FurnitureItems[0].Quantity" ...>
<input type="text" name="FurnitureItems[1].Quantity" ...>
您可以使用 BeginCollectionItem 助手生成控件,它可能看起来像(假设 属性 被命名为 FurnitureItems
)
@model CdvPortal.Models.BistroReservations.BistroReservations_ReservationFurniture
@using (Html.BeginCollectionItem("FurnitureItems"))
{
....
@Html.LabelFor(m => m.Quantity, ..)
@Html.EditorFor(m => m.Quantity, ..)
@Html.ValidationMessageFor(m => m.Quantity, ..)
}
这将生成正确的前缀并添加一个基于 guid
的索引器,它还允许您从集合中删除项目。 This article 更详细地解释了用法
中显示了纯客户端替代方案。这提供了更好的性能,但更难维护,因为更改 BistroReservations_ReservationFurniture
模型中的任何内容都意味着更新客户端模板。
我正在构建一个餐厅预订系统。当用户创建预订时,他们还可以决定将在预订中使用哪些家具。为此,我创建了一个局部视图,因此每次用户单击 "add furniture" 时,局部视图都会加载 ajax,然后用户可以在其中指定家具的种类和数量。他们可以根据需要添加任意数量的家具,这意味着他们可以根据需要多次调用分部视图。我的问题来自模型绑定器,然后模型绑定器将所有这些部分视图实例绑定到类型 "BistroReservations_ReservationsFurniture" 的列表对象。请帮助如何使模型活页夹工作。
MainView(请查看底部的 ajax.actionlink 调用 "Add Furniture"
@using (Html.BeginForm())
{ @Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>BistroReservations_Reservation</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.DateOfArrival, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.DateOfArrival, new { htmlAttributes = new { @class = "form-control datecontrol" } })
@Html.ValidationMessageFor(model => model.DateOfArrival, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.BistroReservations_ShiftID, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("BistroReservations_ShiftID", null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.BistroReservations_ShiftID, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.BistroReservations_GuestID, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-6">
@Html.DropDownList("BistroReservations_GuestID", null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.BistroReservations_GuestID, "", new { @class = "text-danger " })
@Ajax.ActionLink("Create a New Guest", "NewGuest", new AjaxOptions
{
HttpMethod = "GET",
UpdateTargetId = "NewGuest",
InsertionMode = InsertionMode.ReplaceWith,
})
</div>
</div>
<div id="NewGuest" class="form-group">
</div>
<br />
<div class="form-group">
@Html.LabelFor(model => model.ArrivalTime, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("ArrivalTime", null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.ArrivalTime, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.LocationID, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("LocationID", null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.LocationID, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.BistroReservations_TypeOfSeatingID, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("BistroReservations_TypeOfSeatingID", null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.BistroReservations_TypeOfSeatingID, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.TableNoID, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("TableNoID", null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.TableNoID, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.BistroReservations_StatusID, "BistroReservations_StatusID", htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("BistroReservations_StatusID",null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.BistroReservations_StatusID, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Comment, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor( model => model.Comment, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Comment, "", new { @class = "text-danger" })
@Ajax.ActionLink("Add Furniture", "Furniture", new AjaxOptions
{
HttpMethod = "GET",
UpdateTargetId = "Furniture",
InsertionMode = InsertionMode.InsertAfter
})
</div>
</div>
<div id="Furniture" class="form-group">
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
返回家具局部视图的ActionResult
public PartialViewResult Furniture()
{
ViewBag.BistroReservations_FurnitureID = new SelectList(db.BistroReservations_Furnitures, "BistroReservations_FurnitureID", "Description");
return PartialView("_Furniture");
}
家具局部视图
@model CdvPortal.Models.BistroReservations.BistroReservations_ReservationFurniture
<div class="form-horizontal">
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.BistroReservations_FurnitureID, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("BistroReservations_FurnitureID", null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.BistroReservations_FurnitureID, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group ">
@Html.LabelFor(model => model.Quantity, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Quantity, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Quantity, "", new { @class = "text-danger" })
</div>
</div>
</div>
家具模型
public class BistroReservations_ReservationFurniture
{
public int BistroReservations_ReservationFurnitureID { get; set; }
public int BistroReservations_ReservationID { get; set; }
public virtual BistroReservations_Reservation BistroReservations_Reservation { get; set; }
[Display(Name="Furniture Type")]
public int BistroReservations_FurnitureID { get; set; }
public virtual BistroReservations_Furniture BistroReservations_Furniture { get; set; }
public int Quantity { get; set; }
}
您 @Ajax.ActionLink()
方法返回的视图具有重复的 id
属性(无效 html)和重复的 name
属性,这些属性没有正确的前缀 属性 名称并且不包括用于绑定到集合的索引器。例如,如果集合 属性 被命名为 FurnitureItems
,那么 typeof BistroReservations_ReservationFurniture
的 Quantity
属性 所需的 html 需要是
<input type="text" name="FurnitureItems[0].Quantity" ...>
<input type="text" name="FurnitureItems[1].Quantity" ...>
您可以使用 BeginCollectionItem 助手生成控件,它可能看起来像(假设 属性 被命名为 FurnitureItems
)
@model CdvPortal.Models.BistroReservations.BistroReservations_ReservationFurniture
@using (Html.BeginCollectionItem("FurnitureItems"))
{
....
@Html.LabelFor(m => m.Quantity, ..)
@Html.EditorFor(m => m.Quantity, ..)
@Html.ValidationMessageFor(m => m.Quantity, ..)
}
这将生成正确的前缀并添加一个基于 guid
的索引器,它还允许您从集合中删除项目。 This article 更详细地解释了用法
BistroReservations_ReservationFurniture
模型中的任何内容都意味着更新客户端模板。