MVC binding to model with list property ignores other properties
asp.net-mvc-3
Solution
Try to change the code for the Data collection to this, and let MVC take care of the naming:
<div class="editor-field">
@for (int i = 0; i < Model.Data.Count(); i++)
{
@Html.HiddenFor(m => m.Data[i].Id)
@Html.HiddenFor(m => m.Data[i].ParentId)
@Html.HiddenFor(m => m.Data[i].Name)
@Html.TextBoxFor(m => m.Data[i].Value)
}
</div>
Problem
I have a basic ViewModel with a property that is a List of complex types. When binding, I seem to be stuck with getting either the list of values, OR the other model properties depending on the posted values (i.e. the view arrangement). The view model: ``` public class MyViewModel { public int Id { get; set; } public string Property1 { get; set; } public string Property2 { get; set; } public List<MyDataItem> Data { get; set; } } public class MyDataItem { public int Id { get; set; } public int ParentId { get; set; } public string Name { get; set; } public string Value { get; set; } } ``` The controller actions: ``` public ActionResult MyForm() { MyViewModel model = new MyViewModel(); model.Id = 1; model.Data = new List<MyDataItem>() { new MyDataItem{ Id = 1, ParentId = 1, Name = "MyListItem1", Value = "SomeValue"} }; return View(model); } [HttpPost] public ActionResult MyForm(MyViewModel model) { //... return View(model); } ``` Here is the basic view (without the list mark-up) ``` @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>My View Model</legend> @Html.HiddenFor(model => model.Id) <div class="editor-label"> @Html.LabelFor(model => model.Property1) </div> <div class="editor-field"> @Html.EditorFor(model => model.Property1) @Html.ValidationMessageFor(model => model.Property1) </div> <div class="editor-label"> @Html.LabelFor(model => model.Property2) </div> <div class="editor-field"> @Html.EditorFor(model => model.Property2) @Html.ValidationMessageFor(model => model.Property2) </div> <p> <input type="submit" value="Save" /> </p> </fieldset> } ``` When posted back to the controller, I get the 2 property values and a null value for the 'Data' property as expected. If I add the mark-up for the List as follows (based on the information in this Scott Hanselman post and Phil Haack's post): ``` <div class="editor-field"> @for (int i = 0; i < Model.Data.Count(); i++) { MyDataItem data = Model.Data[i]; @Html.Hidden("model.Data[" + i + "].Id", data.Id) @Html.Hidden("model.Data[" + i + "].ParentId", data.ParentId) @Html.Hidden("model.Data[" + i + "].Name", data.Name) @Html.TextBox("model.Data[" + i + "].Value", data.Value) } </div> ``` The 'Data' property of the model is successfully bound but the other properties are null. The form values posted are as follows: ``` Id=1&Property1=test1&Property2=test2&model.Data%5B0%5D.Id=1&model.Data%5B0%5D.ParentId=1&model.Data%5B0%5D.Name=MyListItem1&model.Data%5B0%5D.Value=SomeValue ``` Is there a way to get both sets of properties populated or am I just missing something obvious? EDIT: For those of you who are curious. Based on the answer from MartinHN, the original generated mark-up was: ``` <div class="editor-field"> <input id="model_Data_0__Id" name="model.Data[0].Id" type="hidden" value="1" /> <input id="model_Data_0__ParentId" name="model.Data[0].ParentId" type="hidden" value="1" /> <input id="model_Data_0__Name" name="model.Data[0].Name" type="hidden" value="MyListItem1" /> <input id="model_Data_0__Value" name="model.Data[0].Value" type="text" value="SomeValue" /> </div> ``` The new generated mark-up is: ``` <div class="editor-field"> <input id="Data_0__Id" data-val="true" name="Data[0].Id" type="hidden" value="1" data-val-number="The field Id must be a number." data-val-required="The Id field is required." /> <input id="Data_0__ParentId" name="Data[0].ParentId" type="hidden" value="1" data-val="true" data-val-number="The field ParentId must be a number." data-val-required="The ParentId field is required." /> <input id="Data_0__Name" name="Data[0].Name" type="hidden" value="MyListItem1" /> <input id="Data_0__Value" name="Data[0].Value" type="text" value="SomeValue" /> </div> ``` Which results in the following posted values: ``` Id=1&Property1=test1&Property2=test2&Data%5B0%5D.Id=1&Data%5B0%5D.ParentId=1&Data%5B0%5D.Name=MyListItem1&Data%5B0%5D.Value=SomeValue ``` Notice there's no 'model.' in the name and posted values...