Post an HTML Table to Ado.Net Datatable

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
}

Datatable to html Table

use this function:

    public static string ConvertDataTableToHTML(DataTable dt)
{
string html = "<table>";
//add header row
html += "<tr>";
for(int i=0;i<dt.Columns.Count;i++)
html+="<td>"+dt.Columns[i].ColumnName+"</td>";
html += "</tr>";
//add rows
for (int i = 0; i < dt.Rows.Count; i++)
{
html += "<tr>";
for (int j = 0; j< dt.Columns.Count; j++)
html += "<td>" + dt.Rows[i][j].ToString() + "</td>";
html += "</tr>";
}
html += "</table>";
return html;
}

Grab values from html c# Datatable Row and Post them outside iframe

You could try something like this:
https://dotnetfiddle.net/GJRsag

Import Excel with HTML Format to DataTable

if the HTML is well formed you can try to load it as XML. Expanding a bit with a very simple example:

        System.Xml.Linq.XDocument html = System.Xml.Linq.XDocument.Load (@"[xls doc]");
//this will pull all the Table Headers.
var q = from th in html.Descendants ("th") select (string)th.Value;

Sharepoint List to ADO.Net data table

Or using the GetDataTable method in the OM:

SPWeb oWebsite = SPContext.Current.Web;
SPList oList = oWebsite.Lists["List_Name"];
SPListItemCollection collListItems = oList.Items;

DataGrid1.DataSource = collListItems.GetDataTable();
DataGrid1.DataBind();

How do I dynamically create, and populate a Table (DataTable?)

Well, the issue (and difficult challenge) is that you thinking of a table in HTML and markup on the page. The problem is that 'table' as HTML is just markup, and as a result, REALLY difficult to work with.

So, what you want to do is at a conceptial level split out (seperate) your UI display of the table, and the the actual table you create in code.

So, think of the problem this way:

code + a table in memory.

HTML markup - display of the table.

So, once we split the two concepts?

Well, now you create that table, add rows to that table, maybe loop and sum a column on that table.

AND THEN display + render the results of that table.

Note the separation here. We have a data table. We do whatever we want with that table, AND THEN RENDER the table in HTML.

Note how we thus don't try to loop, try to modify, try to change the HTML table. (its too painful).

The other bonus? Well, in most cases we can assume you have a database. Thus, once again, the concept of the data, the data operations are 100% separate from what we going to display to the UI.

So, think data table operations. Do whatever.

THEN we render + display that table.

The above also means then we can use one of the "many" data repeating controls to do all the heavy lifting of the "display", but the code never really hits, touches, and attempts to modify the HTML - we only "render" the data AFTER we done our data operations.

if you break the above concept (data operations, and HMTL UI operations), then you have to start writing boatloads of code to try and update the HTML, but worse, the HTML is ONLY a representation of that internal data table anyway.

So, MUCH less work to do data operations, and when done, then just have asp.net do this:

Mr. asp.net, can you now just display my table for me? (especially after I done my data operations).

Since asp.net net can render + display that data table, and do so without looping or me having to write that code, then that's the approach I recommend.

my plan was to traverse each row in the table until i found the place I wanted to add a new row of data,

Caution!!!! - you don't really have a "place" in your data. You add a row of data to the system, and then query or pull or sort the data in the order you want. Data operations as a general rule does NOT have a order. You might have some invoice number, or some other column that you can (or want to) sort on, but again, thinking of data like old style punched cards in which order matters is a LESS then ideal way to think of data.

Your data is a bucket of rows. You do operations against that data, and THEN send it to the browser to be rendered as a table. Again, note the concept that we have data - a thing that is separate from display. As noted, we don't want to try and think of HTML as some table - it is ONLY for display - its only markup.

So, the first issue we deal with?

Where and how did this data come from in the first place? I mean, it rare as a cold day in hell that the data JUST appears out of now place. So, first up, is do you have, or are you using a database? (and note that since you NOT talked about that database system, this is the VERY reason why you are struggling here).

So, I can pick a repeater, GridView, ListView (my favorite), or many more controls that can display this data for you, but manipulation of the data? Nope - that occurs at the data level - not the UI level. Keep these two concepts separate.

So, where is this data coming from in the first place? Do you have this as a data table and database some place? I mean, you posted a screen shot of the data, but it can't just appear by magic, can it?

So, this is the first issue, first order of the day. Where is this data coming from? That's the first part of this puzzle. That data resides some place, and that is a good thing, but it not a HTML table - it is some data in a system that exists some place, and that is our starting point for this. Be this ms-access, FoxPro, Excel or some such?

that data comes from some place, and it exists. It would not make sense that every time we launch the program, that we re-type the data all over again. So, the where, the when, and the source of this data?

Note how you LEFT OUT this detail!!!! - and that's why we are struggling here!

So, say I have a table with some hotels. Well, then I can render (display) the data as some type of HTML table - and might as well let asp.net do that dirty work for us.

So, say we have this markup. In fact, I used the wizard, AND THEN blew out the sql data source that gets placed on the page (I want more control over the data with code).

So, say we have this markup:

    <div id="MyGrid" runat="server" style="width:40%">
<asp:Button ID="cmdAdd" runat="server" Text="+Add New" CssClass="btn" />
<asp:GridView ID="GHotels" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" CssClass="table">
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:TemplateField HeaderText="Edit">
<ItemTemplate>
<asp:Button ID="cmdEdit" runat="server" Text="Edit" CssClass="btn"
OnClick="cmdEdit_Click" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<br />
</div>

So, I dropped in a grid view. (but, with your sample markup, a listView probably is better).

Now, we have this code to load up the above:

 Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

If Not IsPostBack Then
LoadGrid()
End If

End Sub

Sub LoadGrid()

Dim cmdSQL As New SqlCommand("SELECT * FROM tblHotelsA ORDER BY HotelName")
Dim rstData as DataTable = MyrstP(cmdSQL)
GHotels.DataSource = rstData
GHotels.DataBind()

End Sub

Public Function MyrstP(sqlCmd As SqlCommand) As DataTable

Dim rstData As New DataTable
Using sqlCmd
Using conn = New SqlConnection(My.Settings.TEST4)
conn.Open()
sqlCmd.Connection = conn
rstData.Load(sqlCmd.ExecuteReader)
End Using
End Using
Return rstData

End Function

Ok, and now we have this:

Sample Image

Note careful:

We did not write loops to load up the HTML.

We use the ado.net data table to get the data. And THEN SEND that data table to the HTML system to display.

Note how we NOT directly working with the HMTL - since well, it is JUST HTML, and as NO business try to be a data system for us - but is great for display!

So, in above, we have a add new button at the top. That could allow us to add a new row to the data base. But, once again, we would add the new row, and then AGAIN send that data (and our new row) to the Gridview, but AGAIN we don't write HTML, we don't try to modify the HTML, and we still have 100% data operations.

Now, no question we might need some markup to edit a single row. That markup to edit ONE row can then be used for our "edit" button, and even our add new button.

So, markup can be used for data entery, but for display of the table and data? That goes and belongs in the database.

So, in above, we might below the grid, drop in some markup that allows edit of one row.

Say, like this:

<div id="EditRecord" runat="server" style="float:left;display: normal" clientidmode="Static"  >
<style>
.iForm label {display:inline-block;width:90px}
.iForm input {border-radius:8px;border-width:1px;margin-bottom:10px}
.iForm textarea {border-radius:8px;border-width:1px;margin-bottom:10px}
.iForm input[type=checkbox] {margin-right:8px}
</style>

<div style="float:left" class="iForm">
<label>HotelName</label><asp:TextBox ID="txtHotel" runat="server" f="HOtelName" width="280"></asp:TextBox> <br />
<label>First Name</label><asp:TextBox ID="tFN" runat="server" f="FirstName" Width="140"></asp:TextBox> <br />
<label>Last Name</label><asp:TextBox ID="tLN" runat="server" f="LastName" Width="140"></asp:TextBox> <br />
<label>City</label><asp:TextBox ID="tCity" runat="server" f="City" Width="140"></asp:TextBox> <br />
<label>Province</label><asp:TextBox ID="tProvince" runat="server" f="Province" Width="75"></asp:TextBox> <br />
</div>
<div style="float:left;margin-left:20px" class="iForm">
<label>Description</label> <br />
<asp:TextBox ID="txtNotes" runat="server" Width="400" TextMode="MultiLine"
Height="150px" f="Description" ></asp:TextBox> <br />
<asp:CheckBox ID="chkActive" f="Active" Text=" Active" runat="server" TextAlign="Right" />
<asp:CheckBox ID="chkBalcony" f="Balcony" Text=" Has Balcony" runat="server" TextAlign="Right" />
</div>
<div style="clear:both"></div>
<button id="cmdSave" runat="server" class="btn" onserverclick="cmdSave_ServerClick" >
<span aria-hidden="true" class="glyphicon glyphicon-floppy-saved"> Save</span>
</button>

<button id="cmdCancel" runat="server" class="btn" style="margin-left:15px"
onserverclick="cmdCancel_ServerClick"
>
<span aria-hidden="true" class="glyphicon glyphicon-arrow-left"> Back/Cancel</span>
</button>

<button id="cmdDelete" runat="server" class="btn" style="margin-left:15px">
<span aria-hidden="true" class="glyphicon glyphicon-trash"> Delete</span>
</button>
</div>

So, that is some markup, and then we have tht button click for each row.

Our code for that click can look like this:

Protected Sub cmdEdit_Click(sender As Object, e As EventArgs)

Dim btn As Button = sender
Dim gRow As GridViewRow = btn.NamingContainer
Dim pkID = GHotels.DataKeys(gRow.RowIndex).Item("ID")

Dim cmdSQL As New SqlCommand("SELECT * from tblHotelsA where ID = @ID")
cmdSQL.Parameters.Add("@ID", SqlDbType.Int).Value = pkID
Dim rstData As DataTable = MyrstP(cmdSQL)

Call fLoader(Me.EditRecord, rstData.Rows(0)) ' load up hidden div with data
' hide grid
MyGrid.Style.Add("display", "none")
EditRecord.Style.Add("display", "normal")
ViewState("rstData") = rstData

End Sub

Again, note how we do data operations against the database - NOT the HTML table!!! - we certainly did use the "UI" and row click of the grid to get that one row to work on, but after that we RIGHT BACK to useing datatable, and data operations against the database and NOT AGAINST the HTML markup.

So, when you click on a row, we get the row "PK" data id, pull the data, load up some controls on the page, hide the grid, show the "div" that has above. We now get this:

Sample Image

Now, this post is already a bit long, and I could post more code. So, in above, the save button would:

Send data back to database (again, database - not touch the grid view or "table"

Then we re-load the grid view from database

Then we hide our div to edit, and show the div with the grid view to display any edits we made.

this code:

Protected Sub cmdSave_ServerClick(sender As Object, e As EventArgs)

Dim rstData As DataTable = ViewState("rstData")
Call fWriterW(EditRecord, rstData.Rows(0)) ' div to table
Call SaveTable(rstData, "tblHotelsA") ' send table back to database

LoadGrid() ' refresh grid
MyGrid.Style.Add("display", "normal")
EditRecord.Style.Add("display", "none")

End Sub

So, the FIRST question we have and need to know here?

Where is your data now, how do you plan to load + read this data. This is the first step, and worry about some HTML markup to display that data actually is the easy part - but the source and getting that data - now that's the important part of this question and process.

I should note that I come from a ms-access, VB6, FoxPro background (desktop). So, you note the above style of code - looks a lot like VBA due to my roots. But, I did make + build a few helper routines used above, (like fLoader, fWirter) that makes such code easy to write.

So, your first issue? Where does the data come from now, and have you setup a valid connection and means to pull that data into a "data table", of which we THEN can send to the browser as HTML.

Edit -- I see you note that you have 4 store procedures. So yes then you can pull that data to a datatable, and then send that datatable to a GridView or say a listview.

In fact, given your existing markup, then I would suggest a listview. As noted, I often use the wizard to build the listview (or gridview). I then blow out (delete) the sql data source that the wizard creates, and as noted, removed the extra templates.

So, you have a table layout that would work quite well as a ListView.

So, taking your existing markup, say this:

It will look somthing like this:

    <div style="width:60%;padding:25px">
<asp:ListView ID="ListView1" runat="server" DataKeyNames="ID" >
<LayoutTemplate>
<table id="itemPlaceholderContainer" runat="server" border="0" class="table table-hover table-bordered" >
<tr runat="server" style="">
<th runat="server">Site Plan</th>
<th runat="server" style="text-align:center">Date<br />(MM/DD/YYYY)</th>
<th runat="server" colspan="2">Number of Days to Complete Action</th>
<th runat="server">PWO</th>
</tr>
<tr id="itemPlaceholder" runat="server">
</tr>
</table>
</LayoutTemplate>

<ItemTemplate>
<tr id ="ECOSubmitRow">
<td>
<asp:Label ID="lblSubmittedToECO" runat="server" Text="Site Plan Submitted to ECO for Approval: "></asp:Label>
</td>
<td>
<asp:Label ID="PlanDate" runat="server" Text="MM/DD/YYYY"></asp:Label>
</td>
<td>
<asp:Label ID="lblPMO" runat="server" Text="PWO: "></asp:Label>
</td>
<td>
<asp:TextBox ID="txtPMO" runat="server"></asp:TextBox>
</td>
</tr>
</ItemTemplate>
</asp:ListView>

So, we have kind of this now:

Sample Image

and in fact, for the actual data, we only need ONE row.

so, looking at this, note how I suggested a list view.

I don't have your data - so, I can't really do a lot in a simple post on SO but lets re-create the first hotel grid, but using the List view.

Note how the layout is "very" simular to a table.

So, for the Hotel grid, using a ListView, then we have this:

        <asp:ListView ID="ListView1" runat="server" DataKeyNames="ID"  >
<LayoutTemplate>
<table id="itemPlaceholderContainer" runat="server" border="0" class="table table-bordered">
<tr runat="server" style="">
<th runat="server">FirstName</th>
<th runat="server">LastName</th>
<th runat="server">HotelName</th>
<th runat="server">Active</th>
<th runat="server">Description</th>
</tr>
<tr id="itemPlaceholder" runat="server">
</tr>
</table>
</LayoutTemplate>

<ItemTemplate>
<tr style="">
<td><asp:Label ID="FirstNameLabel" runat="server" Text='<%# Eval("FirstName") %>' /></td>
<td><asp:Label ID="LastNameLabel" runat="server" Text='<%# Eval("LastName") %>' /></td>
<td><asp:Label ID="HotelNameLabel" runat="server" Text='<%# Eval("HotelName") %>' /></td>
<td style="text-align:center">
<asp:CheckBox ID="ActiveCheckBox" runat="server" Checked='<%# Eval("Active") %>' />
</td>
<td><asp:Label ID="DescriptionLabel" runat="server" Text='<%# Eval("Description") %>' /></td>
</tr>
</ItemTemplate>
</asp:ListView>

Note again, VERY simular to a HTML table, but we use ListView, since it is like GridView a data bound control. And we can then feed it that data table.

So, my code to load this list view, is this:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadGrid
End If
End Sub


Sub LoadGrid()

Dim cmdSQL = New SqlCommand("SELECT * FROM tblHotelsA ORDER BY HotelName")
Dim rstData As DataTable
rstData = MyrstP(cmdSQL)

ListView1.DataSource = rstData
ListView1.DataBind()

End Sub

And I get this:

Sample Image

So, while the GridView is "quick and dirty" as you layout becomes a little more complex, then ListView becomes a better choice - and its layout VERY much follows a HTML table, but the big deal is of course that you can feed it a data table - so, we don't try to create the HTML table or markup - we setup a layout, and feed it that data table.



Related Topics



Leave a reply



Submit