Post an HTML Table to ADO.NET DataTable

C#asp.net MvcRazorasp.net Mvc-5

C# Problem Overview


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; }
}

C# Solutions


Solution 1 - C#

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
}

Solution 2 - C#

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>
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRKhView Question on Stackoverflow
Solution 1 - C#user3559349View Answer on Stackoverflow
Solution 2 - C#lashjaView Answer on Stackoverflow