当相同的局部视图的多个实例动态地调用ajax.actionlink MVC中5模型结合不起作用多个、视图、局部、实例

2023-09-10 20:22:19 作者:往事成风泪已干

我要建一个餐厅预订系统。当用户创建一个预订他们也可以决定什么家具将与预约使用。为此,我创建了一个局部视图,所以添加家具的局部视图,用户点击装有阿贾克斯每一次,用户就可以指定哪些家具和多少。因为他们希望他们可以添加多种类型的家具,这意味着它们可以调用局部视图多次他们想要的。我的问题来自与模型绑定,模型绑定则已经绑定所有的局部视图实例类型的列表对象BistroReservations_ReservationsFurniture。请帮助如何使模型绑定工作。

的MainView(请看看底部的ajax.actionlink呼叫添加家具

  @using(Html.BeginForm())
 

{     @ Html.AntiForgeryToken()

 < D​​IV CLASS =形横>
    < H4> BistroReservations_Reservation< / H4>
    <小时/>
    @ Html.ValidationSummary(真的,,新{@class =文本危险})
    < D​​IV CLASS =形组>
        @ Html.LabelFor(型号=> model.DateOfArrival,htmlAttributes:新{@class =控制标签COL-MD-2})
        < D​​IV CLASS =COL-MD-10>
            @ Html.EditorFor(型号=> model.DateOfArrival,新{htmlAttributes =新{@class =形式控制datecontrol}})
            @ Html.ValidationMessageFor(型号=> model.DateOfArrival,,新{@class =文本危险})
        < / DIV>
    < / DIV>

    < D​​IV CLASS =形组>
        @ Html.LabelFor(型号=> model.BistroReservations_ShiftID,htmlAttributes:新{@class =控制标签COL-MD-2})
        < D​​IV CLASS =COL-MD-10>
            @ Html.DropDownList(BistroReservations_ShiftID,空,htmlAttributes:新{@class =表单控制})
            @ Html.ValidationMessageFor(型号=> model.BistroReservations_ShiftID,,新{@class =文本危险})
        < / DIV>
    < / DIV>

< D​​IV CLASS =形组>
    @ Html.LabelFor(型号=> model.BistroReservations_GuestID,htmlAttributes:新{@class =控制标签COL-MD-2})
    < D​​IV CLASS =COL-MD-6>
        @ Html.DropDownList(BistroReservations_GuestID,空,htmlAttributes:新{@class =表单控制})
        @ Html.ValidationMessageFor(型号=> model.BistroReservations_GuestID,,新{@class =文本危险})

        @ Ajax.ActionLink(创建新客户,NewGuest,新AjaxOptions
       {
           HttpMethod =GET,
           UpdateTargetId =NewGuest
           InsertionMode = InsertionMode.ReplaceWith,
       })
    < / DIV>
< / DIV>

    < D​​IV ID =NewGuest级=形组>
    < / DIV>
    < BR />

    < D​​IV CLASS =形组>
        @ Html.LabelFor(型号=> model.ArrivalTime,htmlAttributes:新{@class =控制标签COL-MD-2})
        < D​​IV CLASS =COL-MD-10>
            @ Html.DropDownList(ArrivalTime,空,htmlAttributes:新{@class =表单控制})
            @ Html.ValidationMessageFor(型号=> model.ArrivalTime,,新{@class =文本危险})
        < / DIV>
    < / DIV>

    < D​​IV CLASS =形组>
        @ Html.LabelFor(型号=> model.LocationID,htmlAttributes:新{@class =控制标签COL-MD-2})
        < D​​IV CLASS =COL-MD-10>
            @ Html.DropDownList(LocationID,空,htmlAttributes:新{@class =表单控制})
            @ Html.ValidationMessageFor(型号=> model.LocationID,,新{@class =文本危险})
        < / DIV>
    < / DIV>

    < D​​IV CLASS =形组>
        @ Html.LabelFor(型号=> model.BistroReservations_TypeOfSeatingID,htmlAttributes:新{@class =控制标签COL-MD-2})
        < D​​IV CLASS =COL-MD-10>
            @ Html.DropDownList(BistroReservations_TypeOfSeatingID,空,htmlAttributes:新{@class =表单控制})
            @ Html.ValidationMessageFor(型号=> model.BistroReservations_TypeOfSeatingID,,新{@class =文本危险})
        < / DIV>
    < / DIV>

    < D​​IV CLASS =形组>
        @ Html.LabelFor(型号=> model.TableNoID,htmlAttributes:新{@class =控制标签COL-MD-2})
        < D​​IV CLASS =COL-MD-10>
            @ Html.DropDownList(TableNoID,空,htmlAttributes:新{@class =表单控制})
            @ Html.ValidationMessageFor(型号=> model.TableNoID,,新{@class =文本危险})
        < / DIV>
    < / DIV>

    < D​​IV CLASS =形组>
        @ Html.LabelFor(型号=> model.BistroReservations_StatusID,BistroReservations_StatusID,htmlAttributes:新{@class =控制标签COL-MD-2})
        < D​​IV CLASS =COL-MD-10>
            @ Html.DropDownList(BistroReservations_StatusID,空,htmlAttributes:新{@class =表单控制})
            @ Html.ValidationMessageFor(型号=> model.BistroReservations_StatusID,,新{@class =文本危险})
        < / DIV>
    < / DIV>

    < D​​IV CLASS =形组>
        @ Html.LabelFor(型号=> model.Comment,htmlAttributes:新{@class =控制标签COL-MD-2})
        < D​​IV CLASS =COL-MD-10>
            @ Html.EditorFor(型号=> model.Comment,新{htmlAttributes =新{@class =表单控制}})
            @ Html.ValidationMessageFor(型号=> model.Comment,,新{@class =文本危险})

            @ Ajax.ActionLink(添加家具,家具,新AjaxOptions
       {
           HttpMethod =GET,
           UpdateTargetId =家具,
           InsertionMode = InsertionMode.InsertAfter
       })

        < / DIV>
    < / DIV>



    < D​​IV ID =家具级=形组>
    < / DIV>

    < D​​IV CLASS =形组>
        < D​​IV CLASS =COL-MD-偏移2 COL-MD-10>
            <输入类型=提交值=创建级=BTN BTN-默认/>
        < / DIV>
    < / DIV>
< / DIV>
 

}

的ActionResult返回家具局部视图

 公共PartialViewResult家具()
    {

        ViewBag.BistroReservations_FurnitureID =新的SelectList(db.BistroReservations_Furnitures,BistroReservations_FurnitureID,说明);

        返回PartialView(_家具);
    }
 
ajax 更新局部视图,使用Ajax局部更新Razor页面的实例代码

家具局部视图

  @model CdvPortal.Models.BistroReservations.BistroReservations_ReservationFurniture

< D​​IV CLASS =形横>
    <小时/>
    @ Html.ValidationSummary(真的,,新{@class =文本危险})
    < D​​IV CLASS =形组>
        @ Html.LabelFor(型号=> model.BistroReservations_FurnitureID,htmlAttributes:新{@class =控制标签COL-MD-2})
        < D​​IV CLASS =COL-MD-10>
            @ Html.DropDownList(BistroReservations_FurnitureID,空,htmlAttributes:新{@class =表单控制})
            @ Html.ValidationMessageFor(型号=> model.BistroReservations_FurnitureID,,新{@class =文本危险})
        < / DIV>
    < / DIV>

    < D​​IV CLASS =形组>
        @ Html.LabelFor(型号=> model.Quantity,htmlAttributes:新{@class =控制标签COL-MD-2})
        < D​​IV CLASS =COL-MD-10>
            @ Html.EditorFor(型号=> model.Quantity,新{htmlAttributes =新{@class =表单控制}})
            @ Html.ValidationMessageFor(型号=> model.Quantity,,新{@class =文本危险})
        < / DIV>
    < / DIV>
< / DIV>
 

家具型号

 公共类BistroReservations_ReservationFurniture
{
    公众诠释BistroReservations_ReservationFurnitureID {获得;组; }

    公众诠释BistroReservations_ReservationID {获得;组; }
    公共虚拟BistroReservations_Reservation BistroReservations_Reservation {获得;组; }

    [显示(名称为家具类型)
    公众诠释BistroReservations_FurnitureID {获得;组; }
    公共虚拟BistroReservations_Furniture BistroReservations_Furniture {获得;组; }

    公众诠释数量{获得;组; }
}
 

解决方案

@ Ajax.ActionLink()方法将返回重复的意见 ID 属性(无效的HTML)和重复名称属性,这是不pfixed使用正确的属性名称$ P $,不包括索引用于结合采集。例如,如果集合属性被命名为 FurnitureItems 然后在需要的数量的HTML 中的typeof BistroReservations_ReservationFurniture 将需要

 <输入类型=文本名称=FurnitureItems [0] .Quantity...>
<输入类型=文本名称=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,..)
}
 

这将产生正确的preFIX并添加包括基于索引器一个的GUID 这也可以让你删除的藏品。 本文更详细地解释的使用

一个纯客户端的替代显示在this回答。这提供了更好的性能,但是很难,因为改变 BistroReservations_ReservationFurniture 模式中有任何手段维护更新客户端模板。

I'm building a restaurant reservations system. When the user creates a reservation they can also decided what furniture will be used with the reservation. For this I created a partial view, so every time the user click on "add furniture" the partial view is loaded with ajax where the user can then specify what furniture and how many. They can add as many types of furniture as they want, meaning they can call the partial view as many times as they want. My problem comes in with the model binder, the model binder then have bind all those partial view instances to a list object of type "BistroReservations_ReservationsFurniture". Please help how to make the model binder work.

MainView (Please have a look at the bottom for the ajax.actionlink call "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 returning the furniture partial view

public PartialViewResult Furniture()
    {

        ViewBag.BistroReservations_FurnitureID = new SelectList(db.BistroReservations_Furnitures, "BistroReservations_FurnitureID", "Description");

        return PartialView("_Furniture");
    }

Furniture partial view

@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>

Furniture Model

 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; }
}

解决方案

You @Ajax.ActionLink() method is returning views with duplicate id attributes (invalid html) and duplicate name attributes which are not prefixed with the correct property name and do not include indexers for binding to a collection. For example if the collection property is named FurnitureItems then the html needed for the Quantity property of typeof BistroReservations_ReservationFurniture would need to be

<input type="text" name="FurnitureItems[0].Quantity" ...>
<input type="text" name="FurnitureItems[1].Quantity" ...>

You can use the BeginCollectionItem helper to generate the controls, which might look like (assuming the property is named 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, ..)
}

This will generate the correct prefix and add include an indexer based on a guid which also allows you to delete items from the collection. This article explains the usage in more detail

A pure client side alternative is shown in this answer. This gives better performance, but is harder to maintain since changing anything in the BistroReservations_ReservationFurniture model means updating the client side template.