Jonesopolis
Jonesopolis

Reputation: 25370

ASP.NET MVC Complex Model Updating

I have a PersonViewModel that consists of several List<SubViewModel> (Name, Address, etc.)

I have an Html Form with tables for each SubViewModel, where the user can update,add,delete and set items to the primary entry for the person.

a simplified table for names:

@foreach (PersonNameViewModel name in Model.Names)
{
  <tr>
     <td>
         @Html.DisplayFor(modelItem => name.FullName)
     </td>
     <td>
         @Html.DisplayFor(modelItem => name.FirstName)
     </td>
     <td>
         @Html.DisplayFor(modelItem => name.MiddleName)
     </td>
     <td>
         @Html.DisplayFor(modelItem => name.LastName)
     </td>
     <td class="center">
         @Html.RadioButtonFor(modelItem => name.IsPrimary, "")
     </td>
     <td class="center">
         @Html.CheckBoxFor(modelItem => name.ToDelete)
     </td>
  </tr>
}

From here, I don't know how to get all the data back into the PersonViewModel when the user submits the form, to update the person record. If I simply accept a PersonViewModel in my POST controller, it's completely empty. I looked at FormCollection, but I'm not sure if that's right for this. Can someone with experience point me in the right direction for building my model back up for updating? Thankyou very much.

Upvotes: 1

Views: 418

Answers (3)

Lin
Lin

Reputation: 15188

Everyone's answer is correct, But if you want to update people's information, you need to use Html Helper Editor NOT Display. Also, you still can use foreach in your view, just change it like below:

@foreach (var name in Model.Names.Select((value, i) => new { i, value }))
{
    <tr>
        <td>
            @Html.EditorFor(m => m.Names[@name.i].FullName)
        </td>
        <td>
            @Html.EditorFor(m => m.Names[@name.i].FirstName)
        </td>
        <td>
            @Html.EditorFor(m => m.Names[@name.i].MiddleName)
        </td>
        <td>
           @Html.EditorFor(m => m.Names[@name.i].LastName)
        </td>
        <td class="center">
            @Html.RadioButtonFor(m => m.Names[@name.i].IsPrimary,"")
        </td>
        <td class="center">
            @Html.CheckBoxFor(m => m.Names[@name.i].ToDelete)
        </td>
    </tr>
}

Upvotes: 3

Todd Menier
Todd Menier

Reputation: 39299

Try replacing the foreach with a for loop:

@for (int i = 0; i < Model.Names.Count; i++)
{
    <tr>
         <td>
                 @Html.DisplayFor(m => m.Names[i].FullName)
         </td>
         <td>
                 @Html.DisplayFor(m => m.Names[i].FirstName)
         </td>
         <td>
                 @Html.DisplayFor(m => m.Names[i].MiddleName)
         </td>
         <td>
                 @Html.DisplayFor(m => m.Names[i].LastName)
         </td>
         <td class="center">
                 @Html.RadioButtonFor(m => m.Names[i].IsPrimary, "")
         </td>
         <td class="center">
                 @Html.CheckBoxFor(m => m.Names[i].ToDelete)
         </td>
    </tr>
}

The expression parsing/model binding does a better job with indexes than with foreach temp variables.

Upvotes: 1

Dmitry Pavliv
Dmitry Pavliv

Reputation: 35853

You should use sth like this (good article about model binding of collections and complex data here):

@for(var i = 0;i < Model.Names.Count;i++)
{
  <tr>
     <td>
         @Html.DisplayFor(m => Model.Names[i].FullName)
     </td>
     <td>
         @Html.DisplayFor(m => Model.Names[i].FirstName)
     </td>
     <td>
         @Html.DisplayFor(m => Model.Names[i].MiddleName)
     </td>
     <td>
         @Html.DisplayFor(m => Model.Names[i].LastName)
     </td>
     <td class="center">
         @Html.RadioButtonFor(m => Model.Names[i].IsPrimary, "")
     </td>
     <td class="center">
         @Html.CheckBoxFor(m => Model.Names[i].ToDelete)
     </td>
  </tr>
}

Upvotes: 1

Related Questions