How to select td inside tfoot with HtmlAgilityPack? - c#

I have this html:
<table>
<thead>
<tr>
<th>Header</th>
</tr>
</thead>
<tbody>
<tr>
<td>Body1</td>
</tr>
<tr>
<td>Body2</td>
</tr>
<tr>
<td>Body3</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>Footer</td>
</tr>
</tfoot>
</table>
I tried to get the Inner.Html of the <td></td> within <tfoot></tfoot>, but I have problem with it.
Here is what I have tried:
var mainGrid = htmlDoc.DocumentNode.SelectSingleNode("//table");
var footerGrid = mainGrid.SelectSingleNode("//tfoot");
var tdFooterGrid = footerGrid.SelectSingleNode("//td");
if (tdFooterGrid != null)
{
var a = tdFooterGrid.InnerHtml;
}
That was fine until I retrieved the footerGrid. When I continued to get the td in order to get the Footer text, it resulted the Body 1 instead.
Is there any suggestion for this?

Below Code will work if you want values inside footer td tag.
var footerGrid = htmlDoc.DocumentNode.SelectSingleNode("//tfoot//td");
if (footerGrid != null)
{
var a = footerGrid.InnerText;
}

Related

How to use a razor declared variable outside of razor?

I have a foreach displaying product descriptions and product prices. i want to be able to sum all of the prices and display them in a data cell. How can i do this?
<table class="table table-striped">
<tr>
<th>Description</th>
<th>Price</th>
</tr>
#foreach (var product in Model)
{
<tr>
<td>#product.Description</td>
<td>#product.Price</td>
</tr>
}
#foreach (var product in Model)
{
var sum = product.Price++;
}
<tr>
<td colspan="2">Total Price: </td>
</tr>
</table>
i want to be able to show the value of sum outside the foreach
You can declare a variable inside a code block and use it in the foreach like so:
<table class="table table-striped">
<tr>
<th>Description</th>
<th>Price</th>
</tr>
#foreach (var product in Model)
{
<tr>
<td>#product.Description</td>
<td>#product.Price</td>
</tr>
}
#{
var sum = 0;
foreach (var product in Model)
{
sum += product.Price;
}
}
<tr>
<td colspan="2">Total Price: #sum</td>
</tr>
</table>
An alternative could be using System.Linq.
<tr>
<td colspan="2">Total Price: #Model.Sum(product => product.Price)</td>
</tr>

HtmlAgilityPack multiple tbody in table

There are multiple Tbodies in a table and I am trying to parse them out by using HTMLagilitypack. Normally the code below would work but it doesn't. Right now it only prints the first tbody and ignores the 2nd.
Code
var tableOffense = doc.DocumentNode.SelectSingleNode("//table[#id='OFF']");
var tbody = tableOffense.SelectNodes("tbody");
foreach(var bodies in tbody)
{
Console.WriteLine("id "+offender.offenderId +" "+ Utilities.RemoveHtmlCharacters(bodies.InnerText));
}
HTML
<table id="OFF" class="centerTable" cols="2" style="margin-top:0; width:100%;" cellpadding="0" cellspacing="0">
<tbody>
<!-- %%$SPLIT -->
<tr> <th id="offenseCodeColHdr" scope="row" style="width:25%;" class="uline">Offense Code</th> <td headers="offenseCodeColHdr" class="uline">288(a)</td> </tr> <tr> <th id="descriptionColHdr" scope="row" style="width:25%;" class="uline">Description</th> <td headers="descriptionColHdr" class="uline">LEWD OR LASCIVIOUS ACTS WITH A CHILD UNDER 14 YEARS OF AGE</td> </tr> <tr> <th id="lastConvictionColHdr" scope="row" style="width:25%;" class="uline">Year of Last Conviction</th> <td headers="lastConvictionColHdr" class="uline"> </td> </tr> <tr> <th id="lastReleaseColHdr" scope="row" style="width:25%;" class="uline">Year of Last Release</th> <td headers="lastReleaseColHdr" class="uline"> </td> </tr>
<tr><th colspan="2"><hr style="height:2px;background-color:#000;"></th></tr> </tbody>
<!-- %%$SPLIT -->
<tbody><tr> <th id="offenseCodeColHdr" scope="row" style="width:25%;" class="uline">Offense Code</th> <td headers="offenseCodeColHdr" class="uline">261(a)(2)</td> </tr> <tr> <th id="descriptionColHdr" scope="row" style="width:25%;" class="uline">Description</th> <td headers="descriptionColHdr" class="uline">RAPE BY FORCE OR FEAR</td> </tr> <tr> <th id="lastConvictionColHdr" scope="row" style="width:25%;" class="uline">Year of Last Conviction</th> <td headers="lastConvictionColHdr" class="uline"> </td> </tr> <tr> <th id="lastReleaseColHdr" scope="row" style="width:25%;" class="uline">Year of Last Release</th> <td headers="lastReleaseColHdr" class="uline"> </td> </tr>
<tr><th colspan="2"><hr style="height:2px;background-color:#000;"></th></tr> </tbody>
<!-- %%$SPLIT -->
</table>
I've printed just the tableOffense node by itself to make sure the 2nd tbody exists at load and it does.
Question
Why does the code only print out the first tbody and not both?
I haven't figured out why your code only gives you one tbody, but may I suggest an alternative solution, to select all your <tbody> elements?
Personally I would make use of XPAth and just select all tbody elements in one go, without an additional SelectNodes():
var tbody = doc.DocumentNode.SelectNodes("//table[#id='OFF']//tbody");
foreach (var elem in tbody)
{
//Dump only works in LinqPad
elem.InnerText.Dump();
}
Edit:
The following code (your code) also yields the same results
var tableOffense = doc.DocumentNode.SelectSingleNode("//table[#id='OFF']");
var tbody = tableOffense.SelectNodes("//tbody");

Creating a table programmatically

I have been searching for quite some time to create the following table through code-behind using C#. I am finding difficulty in adding a <tr> to <thead> and <tr> to <tbody>. This is how the table should look like:
<table id="mytable" border="1" cellpadding="10" cellspacing="0" >
<caption>myCaption</caption>
<thead>
<tr>
<td> </td>
<th scope="col">myHeader1</th>
<th scope="col">myHeader2</th>
<th scope="col">myHeader3</th>
</tr>
</thead>
<tbody>
<tr>
<td>2</td>
<td>3</td>
<td>1</td>
</tr>
</tbody>
</table>
Any help is appreciated.
Create a strongly typed view with a list of whatever you're binding, and use the #foreach loop:
#model List<MyClass>
<table id="mytable" border="1" cellpadding="10" cellspacing="0" >
<caption>myCaption</caption>
<thead>
<tr>
<td> </td>
<th scope="col">myHeader1</th>
<th scope="col">myHeader2</th>
<th scope="col">myHeader3</th>
</tr>
</thead>
<tbody>
#foreach(var m in Model)
{
<tr>
<td>#m.MyProp1</td>
<td>#m.MyProp2</td>
<td>#m.MyProp3</td>
</tr>
}
</tbody>
I have done similar thing using C# MVC. Here is a sample code. Hope this will help to get an idea.
#{int count = Model.HeadingsList.Count;}
<table>
<thead>
<tr>
#foreach (string heading in Model.HeadingsList)
{
<th>#heading</th>
}
</tr>
</thead>
<tbody>
#foreach (string row in Model.rowsList)
{
string[] cellValues = Array.ConvertAll(row.Split(','), p => p.Trim());
if (count != cellValues.Count()) { return; }
<tr>
#for (int i = 0; i < #count; i++)
{
<td>#cellValues[i]</td>
}
</tr>
}
</tbody>
</table>
I had a list of rows like below.
Array[0]['cell1','cell2','cell3'...]
Array[1]['cell1','cell2','cell3'...]

0x800a138f - JavaScript runtime error: Unable to get property 'mData' of undefined or null reference

I am using Datatables version 1.10.6.
In jquery.dataTables.js i am getting above error.
0x800a138f - JavaScript runtime error: Unable to get property 'mData' of undefined or null reference.
$.each( _fnGetRowElements( oSettings, rowOne[0] ).cells, function (i, cell) {
var col = oSettings.aoColumns[i];
if ( col.mData === i ) {// this line gives error
var sort = a( cell, 'sort' ) || a( cell, 'order' );
var filter = a( cell, 'filter' ) || a( cell, 'search' );
if ( sort !== null || filter !== null ) {
col.mData = {
_: i+'.display',
sort: sort !== null ? i+'.#data-'+sort : undefined,
type: sort !== null ? i+'.#data-'+sort : undefined,
filter: filter !== null ? i+'.#data-'+filter : undefined
};
_fnColumnOptions( oSettings, i );
}
}
} );
}
In MVC i am using :
<script type="text/javascript">
$(document).ready(function () {
// Setup - add a text input to each footer cell
$('#example tfoot th').each(function () {
var title = $('#example thead th').eq($(this).index()).text();
$(this).html('<input type="text" placeholder="Search ' + title + '" />');
});
// DataTable
var table = $('#example').DataTable();
alert(table);
// Apply the search
table.columns().every(function () {
var that = this;
$('input', this.footer()).on('keyup change', function () {
that
.search(this.value)
.draw();
});
});
});
</script>
<table class="display" id="example" cellspacing="0">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Employee Id</th>
<th>Active</th>
<th>SFDC</th>
<th>System User</th>
</tr>
</thead>
<tfoot>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Employee Id</th>
<th>Active</th>
<th>SFDC</th>
<th>System User</th>
</tr>
</tfoot>
<tbody>
#foreach (var item in Model)
{
<tr>
<td valign="middle" align="center">
#Html.DisplayFor(modelitem => item.FirstName)
</td>
<td valign="middle" align="center">
#Html.DisplayFor(modelitem => item.LastName)
</td>
<td valign="middle" align="center">
#Html.DisplayFor(modelitem => item.EmailAddress)
</td>
<td valign="middle" align="center">
#Html.DisplayFor(modelitem => item.EmployeeId)
</td>
<td valign="middle" align="center">
#Html.DisplayFor(modelitem => item.IsActive, true)
</td>
<td valign="middle" align="center">
#Html.DisplayFor(modelitem => item.IsSFDC, true)
</td>
<td valign="middle" align="center">
#Html.DisplayFor(modelitem => item.IsSystemUser, true)
</td>
<td valign="middle" align="center">
#Html.ActionLink(" ", "Edit", new { id = item.UserId }, new { #class = "edit_btn", title = "Edit" })
#Html.ActionLink(" ", "Details", new { id = item.UserId }, new { #class = "details", title = "Details" })
#Html.ActionLink(" ", "Delete", new { id = item.UserId }, new { #class = "delete", title = "Delete" })
</td>
</tr>
}
</tbody>
</table>
The mismatch in the number of header columns cause this issue, there should be equal number of header columns and the row columns.
I have added an extra <th></th> eight column was missing
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Employee Id</th>
<th>Active</th>
<th>SFDC</th>
<th>System User</th>
<th></th>
When I got this error I tried the above solutions and after looking at the source code on the webpage, I saw that the entire inner contents of the table was in a <tbody> instead of separated into <thead> and <tbody>. So, make sure you have the following with an equal number of header columns as cells in each row like mentioned above:
<table>
<thead>
<tr>
<th></th>
...
<tr>
</thead>
<tbody>
<tr>
<td></td>
...
</tr>
</tbody>
</table>
After I did this, it worked!
I faced same situation. For my case, due to runat="server" attribute in table tag.
Once removed runat="server" from table declaration, it worked well.
This could also happen when an action attached to a JQuery selector cannot execute successfully for a particular document's element. Therefore, you either change the element's id or fix the action's JavaScript code.

Adding rows to the final page of a pagedlist

<div>
<table ​>
<tr>
<th>Customer ID</th>
<th>Name</th>
<th>Type</th>
</tr>
#foreach (var a in Model.Attachments)
{
<tr>
<td>
#a.CId
</td>
<td>
#a.CName
</td>
<td>
#a.CType
</td>
</tr>
}
</table>
#Html.PagedListPager((IPagedList)Model.Attachments, page => Url.Action("Index", new { page }))
</div>
Currently I am displaying 25 items per page. If the final page does not have 25 items, I want to append rows to the end of the table, to keep the Page selector at the same level from page to page.
This seems like it would work, I just don't know where to put it:
#for (int i = 25; i > Model.Attachments.Count() % 25; i--)
{
<tr>
<td></td>
</tr>
}
You have for sure a loop thrown the attachments list.
Put this loop right after the loop where you write your TRs.
Just take into account that if your data makes your TRs higher, this will break your solution. Other thing you may try is adding a HTML space in your dummy rows:
<div>
<table ​>
<tr>
<th>Customer ID</th>
<th>Name</th>
<th>Type</th>
</tr>
#foreach (var a in Model.Attachments)
{
<tr>
<td>
#a.CId
</td>
<td>
#a.CName
</td>
<td>
#a.CType
</td>
</tr>
}
#for (int i = 25; i > Model.Attachments.Count() % 25; i--)
{
<tr>
<td></td>
</tr>
}
</table>
#Html.PagedListPager((IPagedList)Model.Attachments, page => Url.Action("Index", new { page }))
</div>

Categories

Resources