How to handle nested collections in MVC 5

2019-07-29 07:52发布

问题:

I'm using MVC 5 and I want to have an edit page that allows selection of items from a list, with options for each item selected. So I have a model like this:

public class TemplateEdit
{
    public Guid TemplateId {get; set;}
    public string TemplateName {get; set;}
    public ICollection<MyOption> Options {get; set;}
}

public class MyOption
{
    public Guid MyOptionId {get; set;}
    public Guid TemplateId {get; set;}
    public string OptionName {get; set;}
    public bool Selected {get; set;}
    public ICollection<SubOption> SubOptions {get; set;}
}

public class SubOption
{
    public Guid SubOptionId {get; set;}
    public Guid MyOptionId {get; set;}
    public string SubOptionName {get; set;}
    public bool Selected {get; set;}
}

Let's assume I have LINQ to get the data for this. Now I want to display it. I was hoping to use Editor templates.

In my template-edit.cshtml view I have something like this:

@model TemplateEdit
<div class="form-group col-md-12">
    @Html.ValidationSummary(false, "", new { @class = "text-danger" })
    @Html.HiddenFor(model => model.TemplateId)
</div>

<div class="form-group col-md-12">
    @Html.LabelForRequired(m => m.TemplateName, new {@class = "control-label"})
    @Html.TextBoxFor(m => m.TemplateName, new {@class = "form-control"})
</div>

<div class="col-md-12" style="overflow: auto; height: 350px;">
    @Html.Label("Options Selected")
    <div>
        @Html.EditorFor(m => m.Options);
    </div>
</div>

In MyOption.cshtml EditorTemplate:

@model MyOption
<div class="optionable">

    @Html.HiddenFor(m => m.MyOptionId)
    @Html.HiddenFor(m => m.TemplateId)

    <div class="row">
        <div class="col-md-2">
            @Html.CheckBoxFor(model => model.Selected, new { @class = "form-control optionToggle" })
        </div>

        <div class="col-md-8">
            @Html.DisplayFor(model => model.OptionName, new { @class = "form-control" } )
        </div>
    </div>
    <div class="row options">
        @Html.EditorFor(m => m.SubOptions);
    </div>
</div>

In my SubOption.cshtml EditorTemplate:

@model SubOption
<div class="optionable">

    @Html.HiddenFor(m => m.SubOptionId)
    @Html.HiddenFor(m => m.MyOptionId)

    <div class="row">
        <div class="col-md-2">
            @Html.CheckBoxFor(model => model.Selected, new { @class = "form-control optionToggle" })
        </div>

        <div class="col-md-8">
            @Html.DisplayFor(model => model.SubOptionName, new { @class = "form-control" } )
        </div>
    </div>
</div>

The problem I am having is that when I return the model, I am not getting the SubOption data.

Note:
All the examples I find are for MVC3 or earlier, and use an index method to iterate through the collection. I would try that, except I am using ICollection for the collections.

回答1:

Check what your action looks like in your controller. If you're passing the viewmodel as the parameter it should include your 'SubOptions' collection.

i.e.

    [HttpPost]
    public ActionResult SaveData(MyViewModel model)
    {
    }


回答2:

Change the SubOption.cshtml to look like this:

@model System.Collections.Generic.IEnumerable<SubOption>
@foreach(var option in Model)
{
    <div class="optionable">

       @Html.HiddenFor(m => option.SubOptionId)
       ...

    </div>
}

You're passing a collection to the EditorFor so your template should also work with a collection instead of a single item.