I have a HTML table as below in my View:
<table id="tblCurrentYear">
<tr>
<td>Leave Type</td>
<td>Leave Taken</td>
<td>Leave Balance</td>
<td>Leave Total</td>
</tr>
@foreach (var item in Model.LeaveDetailsList)
{
<tr>
<td>@Html.TextBoxFor(m => item.LeaveType, new { width = "100" })</td>
<td>@Html.TextBoxFor(m => item.LeaveTaken, new { width = "100" })</td>
<td>@Html.TextBoxFor(m => item.LeaveBalance, new { width = "100" })</td>
<td>@Html.TextBoxFor(m => item.LeaveTotal, new { width = "100" })</td>
</tr>
}
</table>
I want to iterate through all the html table rows and insert the values in ADO.NET DataTable.
Simple speaking, converting HTML Table to ADO.NET DataTable.
How to extract values from HTML Table and insert into ADO.NET DataTable?
The view is based on the following model
public class LeaveBalanceViewModel
{
public LeaveBalanceViewModel()
{
this.EmployeeDetail = new EmployeeDetails();
this.LeaveBalanceDetail = new LeaveBalanceDetails();
this.LeaveDetailsList = new List<LeaveBalanceDetails>();
}
public EmployeeDetails EmployeeDetail { get; set; }
public LeaveBalanceDetails LeaveBalanceDetail { get; set; }
public List<LeaveBalanceDetails> LeaveDetailsList { get; set; }
}
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
}
With respect to your requirement, try this
jQuery(document).on("change", ".DDLChoices", function (e) {
var comma_ChoiceIds = '';
var comma_ChoicesText = '';
$('input[class="DDLChoices"]').each(function (e) {
if (this.checked) {
comma_ChoiceIds = comma_ChoiceIds + $(this).val() + ',';
comma_ChoicesText = comma_ChoicesText + $(this).parent('label').parent() + ',';
}
});
$('#ChoiceIds').val(comma_ChoiceIds);
$('#ChoiceText').val(comma_ChoicesText);
});
@using (Html.BeginForm("Actionname", "Controllername", FormMethod.Post, new { id = "frmChoices" }))
{
@Html.HiddenFor(m => m.ChoiceText, new { @id = "ChoiceText" })
@Html.HiddenFor(m => m.ChoiceIds, new { @id = "ChoiceIds" })
<div class="form-group">
<div>
<table>
<tr>
<th>Name</th>
<th>Selected</th>
</tr>
@foreach (var item in @Model.Choices)
{
<tr>
<td> <label>@item.ChoicesText</label> </td>
<td> <input class="DDLChoices" value="@item.ChoiceIds" type="checkbox" /></td>
</tr>
}
</table>
</div>
<input type="button" value="Submit" onclick="return ChoicesPoster.passChoices()"
</div>
}