As you correctly noted, this is due to the fact that you are using partial. This is because Html.Partial does not know that it works in the collection, so it does not generate names for your form elements with the intention of binding them to the collection.
However, the fix in your case seems pretty simple. Instead of using Html.Partial , you can simply change your fragment in the EditorTemplate and call Html.EditorFor in this template. Html.EditorFor is smart enough to know when it is processing the collection, so it will call your template for each element in the collection, generating the correct names in your form.
To do what you need, follow these steps:
- Create the
EditorTemplates folder inside the current current view folder (for example, if your view is Home\Index.cshtml , create the Home\EditorTemplates ). The name is important because it complies with the pattern search agreement. - Place a partial view in this folder. Alternatively, place it in the
Shared\EditorTemplates . - Rename the partial view to
Datapoint.cshtml (this is important because template names are based on type name convention).
Now the corresponding view code will look like this:
// Note: I removed @ from Model here. @foreach (var g in Model) { <h2>@g.Name</h2> @Html.EditorFor(m => g.DataPoints) <hr /> }
This ensures that your views are shared as you originally planned.
Update for comments
Well, as I mentioned below, the problem is that the model binder does not bind a DataPoint to the correct Group in any way. A simple fix is ββto change the view code to this:
for (int i = 0; i < Model.Count; i++) { <h2>@Model[i].Name</h2> @Html.EditorFor(m => m[i].DataPoints) <hr /> }
This will generate the names correctly and should solve the model binding problem.
Op addendum
Following Johnβs answer, I also included the missing properties in the Group table as HiddenFor, in which game the model returned to my post.
@for (int i = 0; i < Model.Count(); i++) { @Html.HiddenFor(t => Model[i].ID) @Html.HiddenFor(t => Model[i].BusinessUnitID) @Html.HiddenFor(t => Model[i].SortOrder) @Html.HiddenFor(t => Model[i].Name) <h2>@Model[i].Name</h2> @Html.EditorFor(m => Model[i].Datapoints) <hr /> }
Update 2 - Cleaning Solution
My advice on using EditorTemplate for each DataPoint also applies to each Group . Instead of needing a for loop, relying on presentation logic again, you can completely avoid this by setting the EditorTemplate for Group . The same steps apply, as indicated above, in terms of placing the template.
In this case, the template will be Group.cshtml and will look like this:
@model Jmp.StaticMeasures.Models.Group <h2>@Model.Name</h2> @Html.EditorFor(m => m.DataPoints) <hr />
As discussed above, this will invoke a template for each item in the collection that will also generate the correct indexes for each Group . Now your initial appearance can be simplified to:
@model List<Jmp.StaticMeasures.Models.Group> @using (Html.BeginForm()) { // Other markup @Html.EditorForModel(); }