Post an HTML Table to ADO.NET DataTable

In order to bind to a model on post back, the name attributes of the form controls must match the model properties. Your use of a foreach loop does not generate the correct name attributes. If you inspect the html you will see multiple instances of

<input type="text" name="item.LeaveType" .../>

but in order to bind to your model the controls would need to be

<input type="text" name="LeaveDetailsList[0].LeaveType" .../>
<input type="text" name="LeaveDetailsList[1].LeaveType" .../>

etc. The easiest way to think about this is to consider how you would access the value of a LeaveType property in C# code

var model = new LeaveBalanceViewModel();
// add some LeaveBalanceDetails instances to the LeaveDetailsList property, then access a value
var leaveType = model.LeaveDetailsList[0].LeaveType;

Since your POST method will have a parameter name (say model), just drop the prefix (model) and that’s how the name attribute of the control must be. In order to do that you must use either a for loop (the collection must implement IList<T>)

for(int i = 0; i < Model.LeaveDetailsList.Count; i++)
{
    @Html.TextBoxFor(m => m.LeaveDetailsList[i].LeaveType)
    ....
}

or use a custom EditorTemplate (the collection need only implement IEnumerable<T>)

In /Views/Shared/EditorTemplates/LeaveBalanceDetails.cshtml

@model yourAssembly.LeaveBalanceDetails
<tr>
    <td>@Html.TextBoxFor(m => m.LeaveType)</td>
    ....
</tr>

and then in the main view (not in a loop)

<table>
    .... // add headings (preferably in a thead element
    <tbody>
        @Html.EditorFor(m => m.LeaveDetailsList)
    </tbody>
</table>

and finally, in the controller

public ActionResult Edit(LeaveBalanceViewModel model)
{
    // iterate over model.LeaveDetailsList and save the items
}

Leave a Comment