Traversing HTML tables with JavaScript / jQuery using the 'headers' attribute - javascript

Lets say I have the following table:
<table>
<thead>
<tr>
<th id="th_00"> </th>
<th id="th_01">TH 01</th>
<th id="th_02">TH 02</th>
<th id="th_03">TH 03</th>
<th id="th_04">TH 04</th>
</tr>
</thead>
<tbody>
<tr>
<th id="th_10">TH 10</th>
<td headers="th_01 th_10">DATA 11</td>
<td headers="th_02 th_10">DATA 12</td>
<td headers="th_03 th_10">DATA 13</td>
<td headers="th_04 th_10">DATA 14</td>
</tr>
<tr>
<th id="th_20">TH 20</th>
<td headers="th_01 th_20">DATA 21</td>
<td headers="th_02 th_20">DATA 22</td>
<td headers="th_03 th_20">DATA 23</td>
<td headers="th_04 th_20">DATA 24</td>
</tr>
</tbody>
</table>
Is there any native way using JavaScript or jQuery to find a specific cell of data using the headers attribute and the th tags id, or will I have to build the functionality myself?
I am currently using regular expressions and a jQuery('td', 'table tbody').each() loop to retrieve the specific cells I need to use, although this is less than ideal as it loops through each cell individually.

var td = $('td[headers="th_01 th_10"]');
perhaps?

Related

Is there a way to use JavaScript Object with Bootstrap Tables

I am trying to create a covid-19 tables with bootstrap tables I want to display cases newcases death newdeath, But I'm not sure if I can use JavaScript Object to display number.
I add the script <script src="/module/index.js"></script> after the footer.
Github Repo: https://github.com/drjoeycadieux/covid-virus.git
index.js
document.getElementById("cases").innerHTML = cases;
document.getElementById("newCases").innerHTML = newCases;
document.getElementById("death").innerHTML = death;
document.getElementById("newDeath").innerHTML = newDeath;
const dailyOverview = [
{
date: '2021-09-09',
cases: 395155,
newCases: 703,
death: 11297,
newDeath: 1,
},
];
index.html
<table class="table table-striped table-dark">
<thead>
<tr>
<th scope="col">Covid-19 Canada</th>
<th scope="col">Quebec</th>
<th scope="col">Ontario</th>
<th scope="col">Manitoba</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Cases</th>
<td id="cases"></td>
<td id="newCases"></td>
<td id="death"></td>
<td id="newDeath"></td>
</tr>
<tr>
<th scope="row">newCases</th>
<td id="newCases"></td>
<!-- <td>Thornton</td>
<td>#fat</td> -->
</tr>
<tr>
<th scope="row">Death</th>
<td id="death"></td>
<!-- <td>the Bird</td>
<td>#twitter</td> -->
</tr>
<tr>
<th scope="row">newDeath</th>
<td id="newDeath"></td>
<!-- <td>the Bird</td>
<td>#twitter</td> -->
</tr>
</tbody>
</table>
There are a lot of things that need to be fixed or changed or added to the HTML and the JS, but essentially you want to do something like this.
const dailyOverview = [{
date: '2021-09-09',
cases: 395155,
newCases: 703,
death: 11297,
newDeath: 1
}];
// dailyOverview[0] gets the first object, wrapped in braces {}.
// dailyOverview[1] would get the second object in braces.
// adding '.cases', '.newCases', etc. gets the property you want.
document.getElementById("cases").innerHTML = dailyOverview[0].cases;
document.getElementById("newCases").innerHTML = dailyOverview[0].newCases;
document.getElementById("death").innerHTML = dailyOverview[0].death;
document.getElementById("newDeath").innerHTML = dailyOverview[0].newDeath;
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
crossorigin="anonymous">
<table class="table table-striped table-dark">
<thead>
<tr>
<th scope="col">Covid-19 Canada</th>
<th scope="col">Quebec</th>
<th scope="col">Ontario</th>
<th scope="col">Manitoba</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Cases</th>
<td id="cases"></td>
<td id="newCases"></td>
<td id="death"></td>
<td id="newDeath"></td>
</tr>
<tr>
<th scope="row">newCases</th>
<td id="newCases"></td>
<td></td>
<td></td>
</tr>
<tr>
<th scope="row">Death</th>
<td id="death"></td>
<td></td>
<td></td>
</tr>
<tr>
<th scope="row">newDeath</th>
<td id="newDeath"></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
You'll have to figure out how to loop through all the objects in your data and apply them to the table.
Create separate questions if necessary. Most of this has already been asked and answered here. There are also prebuilt JS libraries that could help. (You'll have to search for those. Asking about libraries isn't allowed on SO.)

Get a specific row from specific table with JavaScript?

Say my dynamic HTML looks something like this:
<table id="DanishCompanies">
<tr><th>Name</th><th>Employees</th><th>Founded</th></tr>
<tr id="19"><td>Company A</td><td>80</td><td>1980</td></tr>
<tr id="17"><td>Company B</td><td>12</td><td>1910</td></tr>
<tr id="26"><td>Company C</td><td>5000</td><td>2015</td></tr>
</table>
<table id="SwedishCompanies">
<tr><th>Name</th><th>Employees</th><th>Founded</th></tr>
<tr id="10"><td>Company D</td><td>500</td><td>1950</td></tr>
<tr id="12"><td>Company E</td><td>900</td><td>1990</td></tr>
<tr id="17"><td>Company F</td><td>90</td><td>2010</td></tr>
</table>
<table id="NorwegianCompanies">
<tr><th>Name</th><th>Employees</th><th>Founded</th></tr>
<tr id="17"><td>Company G</td><td>105</td><td>1970</td></tr>
<tr id="18"><td>Company H</td><td>100</td><td>1980</td></tr>
<tr id="19"><td>Company I</td><td>45</td><td>2000</td></tr>
</table>
Each tr has an ID, but ID only relatively unique to the table, as other tables might have the ID, and the number of rows might vary.
How would I obtain the founding year (column 2) of a Swedish company with an id of 17?
I would imagine you would do it like this but I fail to find the correct code.
var table = document.getElementById("SwedishCompanies");
var row_index = ??? //should return 2
return table[row_index].cells[2].innerHTML;
I can't use getElementById just to get id "17", because I would risk getting Danish or Norwegian's company because the order of these tables is random.
you're just not using the right selector,
#DanishCompanies tr[id="17"]
will get you the tr with id 17 that's a child of DanishCompanies :
const row = document.querySelector('#DanishCompanies tr[id="17"]');
const year = row.cells[2].innerHTML;
console.log(year);
<table id="DanishCompanies">
<tr>
<th>Name</th>
<th>Employees</th>
<th>Founded</th>
</tr>
<tr id="19">
<td>Company A</td>
<td>80</td>
<td>1980</td>
</tr>
<tr id="17">
<td>Company B</td>
<td>12</td>
<td>1910</td>
</tr>
<tr id="26">
<td>Company C</td>
<td>5000</td>
<td>2015</td>
</tr>
</table>
<table id="SwedishCompanies">
<tr>
<th>Name</th>
<th>Employees</th>
<th>Founded</th>
</tr>
<tr id="10">
<td>Company D</td>
<td>500</td>
<td>1950</td>
</tr>
<tr id="12">
<td>Company E</td>
<td>900</td>
<td>1990</td>
</tr>
<tr id="17">
<td>Company F</td>
<td>90</td>
<td>2010</td>
</tr>
</table>
<table id="NorwegianCompanies">
<tr>
<th>Name</th>
<th>Employees</th>
<th>Founded</th>
</tr>
<tr id="17">
<td>Company G</td>
<td>105</td>
<td>1970</td>
</tr>
<tr id="18">
<td>Company H</td>
<td>100</td>
<td>1980</td>
</tr>
<tr id="19">
<td>Company I</td>
<td>45</td>
<td>2000</td>
</tr>
</table>
this way (id with number values complicates the css select syntax)
function getTDval( tableId, rowId, colNum)
{
return document
.querySelector(`table#${tableId} tr[id="${rowId}"]`)
.cells[colNum].textContent
}
console.log( getTDval('SwedishCompanies','17',2) )
<table id="DanishCompanies">
<tr><th>Name</th><th>Employees</th><th>Founded</th></tr>
<tr id="19"><td>Company A</td><td>80</td><td>1980</td></tr>
<tr id="17"><td>Company B</td><td>12</td><td>1910</td></tr>
<tr id="26"><td>Company C</td><td>5000</td><td>2015</td></tr>
</table>
<table id="SwedishCompanies">
<tr><th>Name</th><th>Employees</th><th>Founded</th></tr>
<tr id="10"><td>Company D</td><td>500</td><td>1950</td></tr>
<tr id="12"><td>Company E</td><td>900</td><td>1990</td></tr>
<tr id="17"><td>Company F</td><td>90</td><td>2010</td></tr>
</table>
<table id="NorwegianCompanies">
<tr><th>Name</th><th>Employees</th><th>Founded</th></tr>
<tr id="17"><td>Company G</td><td>105</td><td>1970</td></tr>
<tr id="18"><td>Company H</td><td>100</td><td>1980</td></tr>
<tr id="19"><td>Company I</td><td>45</td><td>2000</td></tr>
</table>
It is invalid HTML to reuse the same id value within a page. You might use private data-... attributes for that.
Apart from that, the following line gets the human readable text of the third child node (third column in this case), which is the year (as a string).
document.querySelector('#DanishCompanies tr[id="17"]')
.children[2].innerText;
If you can't rely on getElmentById that means that you are doing something wrong, an id should be unique in the whole html. I suggest a new naming technique, you can concatenate the parent table id with the current row id. Example:
<table id="NorwegianCompanies">
<tr><th>Name</th><th>Employees</th><th>Founded</th></tr>
<tr id="NorwegianCompanies17"><td>Company G</td><td>105</td><td>1970</td></tr>
<tr id="NorwegianCompanies18"><td>Company H</td><td>100</td><td>1980</td></tr>
<tr id="NorwegianCompanies19"><td>Company I</td><td>45</td><td>2000</td></tr>
</table>
In that way you can simply call
const row = document.getElementById(rowId)

How can I identify an element with no class/ID and won't always be the same nth child?

I've got some text displaying in a table (oldschool, I know) and I'm trying to identify that specific <td> element so I can use jQuery to wrap() <a href> tags around it and convert it to a link.
The problem is, none of the <td>'s in the table have unique classes or ID's, and there will always be an unknown amount of <td>'s before the one I want to access, so I don't think I can use nth of child.
The ONLY unique way that <td> is identifiable is the <td> DIRECTLY before it, which will contain some text that will always be the same. Can I use jQuery to find that <td> based on the text inside it, then target the <td> directly after that? Or is there a better way to do this?
You can use jQuery to fetch element that contains specific text and access the next td as required with a single line of jQuery code. This won't thrown an exception in case when there is no next td.
$(document).ready(function() {
var yourVal = $('td:contains("2.2")').next('td').text();
console.log(yourVal);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<table class="table">
<thead>
<tr>
<th>Col 1</th>
<th>Col 2</th>
<th>Col 3</th>
<th>Col 4</th>
</tr>
</thead>
<tbody>
<tr>
<td>1.1</td>
<td>1.2</td>
<td>1.3</td>
<td>1.4</td>
</tr>
<tr>
<td>2.1</td>
<td>2.2</td>
<td>2.3</td>
<td>2.4</td>
</tr>
<tr>
<td>3.1</td>
<td>3.2</td>
<td>3.3</td>
<td>3.4</td>
</tr>
</tbody>
</table>
You are looking for the nextElementSibling of the <td> with unique textContent. In order to find it, loop over all the <td>s and then get the nextElementSibling of the <td> with unique textContent. And when you find it, break.
const tds = document.querySelectorAll("td")
for (let td of tds) {
if (td.innerText.includes("Larry")) {
const element = td.nextElementSibling
console.log(element.innerText)
break;
}
}
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">First</th>
<th scope="col">Last</th>
<th scope="col">Handle</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">1</th>
<td>Mark</td>
<td>Otto</td>
<td>#mdo</td>
</tr>
<tr>
<th scope="row">2</th>
<td>Jacob</td>
<td>Thornton</td>
<td>#fat</td>
</tr>
<tr>
<th scope="row">3</th>
<td>Larry</td>
<td>the Bird</td>
<td>#twitter</td>
</tr>
</tbody>
</table>
If you like jQuery, use this.
const td = jQuery("td:contains('Larry')").next("td").text()
console.log(td)
<script src="https://cdn.jsdelivr.net/npm/jquery#3.5.1/dist/jquery.min.js"></script>
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">First</th>
<th scope="col">Last</th>
<th scope="col">Handle</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">1</th>
<td>Mark</td>
<td>Otto</td>
<td>#mdo</td>
</tr>
<tr>
<th scope="row">2</th>
<td>Jacob</td>
<td>Thornton</td>
<td>#fat</td>
</tr>
<tr>
<th scope="row">3</th>
<td>Larry</td>
<td>the Bird</td>
<td>#twitter</td>
</tr>
</tbody>
</table>

Sort table in HTML by column with date values desc using only javaScript

Is it possible to make sorting function using only javaScript, without any other library for sorting?
Let's say I have one table, and it's first column that has date values in this format: MM/dd/yyyy. Table has two more columns, like this:
<table id="results" width="360" border="1">
<thead>
<tr>
<th scope="col" width="120">Date Created</th>
<th scope="col" width="120">Name</th>
<th scope="col" width="120">Tests</th>
</tr>
<tr>
<td>07/08/2015</td>
<td>Test Name</td>
<td>Raven</td>
</tr>
<tr>
<td>05/04/2015</td>
<td>Test Name 4</td>
<td>Raven 3</td>
</tr>
<tr/>
<td>01/08/2017</td>
<td>Test Name 2</td>
<td>PCT</td>
</tr>
</thead>
</table>
Would it be possible to lets say add one button, and on click event sort rows by values in Date column?
I have to accomplish this using only plain javaScript and HTML, so no jQuery unfortunately :(
Here's a little something I whipped up to give you some ideas. Obviously you could extend this to sort by other data types.
I've "cheated" on the date comparisons by just changing the string format date directly to an eight-digit number in the form 20140312 from "12/03/2014" - note that I've assumed the date input format is dd/mm/yyyy, so if for some reason you're actually using mm/dd/yyyy you'll have to tweak the convertDate() function.
Also I've introduced a <tbody> into your table so that I can just sort the data rows and completely ignore the header row.
function convertDate(d) {
var p = d.split("/");
return +(p[2]+p[1]+p[0]);
}
function sortByDate() {
var tbody = document.querySelector("#results tbody");
// get trs as array for ease of use
var rows = [].slice.call(tbody.querySelectorAll("tr"));
rows.sort(function(a,b) {
return convertDate(a.cells[0].innerHTML) - convertDate(b.cells[0].innerHTML);
});
rows.forEach(function(v) {
tbody.appendChild(v); // note that .appendChild() *moves* elements
});
}
document.querySelector("button").addEventListener("click", sortByDate);
<table id="results" width="360" border="1">
<thead>
<tr>
<th scope="col" width="120">Date Created</th>
<th scope="col" width="120">Name</th>
<th scope="col" width="120">Tests</th>
</tr>
</thead>
<tbody>
<tr>
<td>04/04/2015</td>
<td>Test Name 2</td>
<td>1</td>
</tr>
<tr>
<td>09/08/2017</td>
<td>Test Name 5</td>
<td>2</td>
</tr>
<tr>
<td>07/08/2015</td>
<td>Test Name 4</td>
<td>3</td>
</tr>
<tr>
<td>05/04/2015</td>
<td>Test Name 3</td>
<td>4</td>
</tr>
<tr>
<td>12/08/2017</td>
<td>Test Name 6</td>
<td>5</td>
</tr>
<tr>
<td>21/03/2014</td>
<td>Test Name 1</td>
<td>6</td>
</tr>
</tbody>
</table>
<button>Sort by date</button>

jQuery sum events on TD click

I have a simple table to simulate a Gantt chart. The idea is that each TD clicking trigger a sum of values stored in an hidden input text (an array of values), available in a TH (first son of TR tag). The row sum of these values, is shown on a final TD.
Next, the code table:
<table width="100%" cellspacing="0" class="datagrid_ppal">
<tbody>
<tr class="encabezado">
<th rowspan="2" scope="col" width="15%">Area</th>
<th colspan="7" scope="col">Month</th>
</tr>
<tr class="encabezado">
<th scope="col" width="2%">1</th>
<th scope="col" width="2%">2</th>
<th scope="col" width="2%">3</th>
<th scope="col" width="2%">4</th>
<th scope="col" width="2%">5</th>
<th scope="col" width="2%">...</th>
<th scope="col" width="2%">31</th>
</tr>
<tr>
<th scope="row">Area 1<input name="line_config" type="hidden" value="0,5,50" /></th>
<td class="gantt"> </td>
<td class="gantt"> </td>
<td class="gantt"> </td>
<td class="gantt"> </td>
<td class="gantt"> </td>
<td class="gantt">...</td>
<td class="gantt"> </td>
</tr>
<tr>
<th scope="row">Area 2 <input name="line_config" type="hidden" value="0,0,10" /></th>
<td class="gantt"> </td>
<td class="gantt"> </td>
<td class="gantt"> </td>
<td class="gantt"> </td>
<td class="gantt"> </td>
<td class="gantt">...</td>
<td class="gantt"> </td>
</tr>
<tr class="encabezado">
<th scope="row">Total</th>
<td class="total_dia"> </td>
<td class="total_dia"> </td>
<td class="total_dia"> </td>
<td class="total_dia"> </td>
<td class="total_dia"> </td>
<td class="total_dia">...</td>
<td class="total_dia"> </td>
</tr>
</tbody>
</table>
The array of values works as follows:
array [0]: Off;
array [1]: preoperative;
array [2]: Operating.
This is the jQuery code I use to differentiate cells that are pre-operational and operational. If a cell is inactive, the area is off:
$(document).ready(function() {
$('td.gantt').click(function() {
$(this).toggleClass('preop');
});
$('td.gantt').dblclick(function() {
$(this).toggleClass('operating');
});
});
Inactive TD always sum to the total. What I want to do? Simple:
1. That jQuery always sum TH input value[0], if the TD is not clicked (inactive).
2. When I click, or double click, a TD.gantt jQuery fetch the TH input value[1], and add it to the total.
If anyone can help with the whole problem, o a parcial, I would really appreciate.
Mixing "click" and "dblclick" is not going to work, at least not reliably. I suggest you re-work the interaction so that "click" cycles through your three different states.
To do the math you want to do (and I don't fully understand that), the basic problem is to get the <th> contents that correspond to the column that each clicked <td> is in. To get that, you'll have to find which child the <td> is of its parent <tr>, and then that will allow you to find the <th> (with the ":nth-child" selector, or the "eq" filter).

Categories

Resources