简体   繁体   中英

How to dynamically add items to my collection from a view when single partial requires multiple objects?

I have a list of items displayed in my view. I need to be able to manually add items to this list from the UI with an add button. I know I need to load a partial view with javascript to get the new item to be displayed.

@{var count = 0;}
@foreach (var dx in Model.Patient.DxList)
{    
    <div class="form-field">
        <label>@(++count)</label>
        @Html.HiddenFor(d => dx.DxIndex)
        @Html.TextBoxFor(d => dx.Dx, new { @class = "small" })
        <span class="description">@((dx.DxRef != null) ? dx.DxRef.Title : "")</span>
        @Html.DropDownListFor(d=> dx.Indicator, new SelectList(Model.Codes, "Value", "Description", dx.Indicator), "Please select", new { @class = "" })
    </div>
}

However, because my item contains both a TextBox and a DropDownList, which is populated with Codes, does my partial view need a ViewModel too? To contain not only the Dx, but the list of appropriate Codes to create the list?

public class DxSingleViewModel
{
    public Dx Dx { get; set; }
    public List<Code> Codes { get; set; }
}

No idea if this is the general approach, or if I'm off base.

You should separate the rendering of one item to a separate partial view / editor template and call it inside your foreach loop, so you have jsut one place where you define the markup for one item:

@foreach (var dx in Model.Patient.DxList)
{
    @Html.EditorFor(m => dx)
}

Then your AddNewItem action can return a partial view which just calls @Html.EditorForModel()

When adding and removing rows dynamically, you should embed your own index (for example a guid string) to the items to avoid collisions. Take a look at this great article which explains how to implement this with a custom html helper: http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/

Your EditorTemplate will look like this:

@using (Html.BeginCollectionItem("DxList"))
{
    @Html.TextBoxFor(d => dx.Dx, new { @class = "small" })
    ....
}

Regarding your question about whether the viewmodel should contain the list for your dropdown or not: The viewmodel should contain every data you need to render the view. So i would say yes, its a good place to pass the list to the view.

Of cause you could pass it in the viewbag too, but i'm a friend of strong typed data bags, so i would prefer the viewmodel.

You can try this approach. It has one downside that you have to remember name (path) of the property to render the right input name for automatic binding (so you cannot easily change it with refactoring tool).

View

@foreach (int i=0;i < Model.Patient.DxList.Count;i++)
{
    @{Html.RenderPartial("PartialDx", Model.Patient.DxList[i] ,new ViewDataDictionary() { {"count",i}});}
}

PartialView - strongly typed partial view with type of DxSingleViewModel

@{string collectionName = string.Format("Patient.DxList[{0}].", ViewBag.count);}

<div class="form-field">
   <label>@{ViewBag.count + 1}</label>
   @Html.Hidden(collectionName+"Dx.DxIndex", Model.Dx.DxIndex)

</div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM