i have an HTML Table which i generate out of my database.
It contains information about machines and their status etc., these informations are parsed out of emails that contain HTML Tables about the machines
That is why i have a click to open/hide <td>
in every tr where i show the "original" HTML Table of the Mail for more details and to better traceability of the results.
All java script functions worked until i added the HTML. Because my filter and search functions iterate through the <tr>
and the <td>
tags, so instead of td.length = 2000 i now have something like td.length = 200000, but i don’t want to iterate through them , because i already parsed that info in the Table with filters etc
So my questions is what is the best way to ignore the HTML in my search function ?
I tried a class like <td id ="ignore me">
or should i do something different like removing it from the table and make a pop up window for it ?
Here is a very simplified version of my HTML Table:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Nested Table Example</title>
<style>
table, th, td {
border: 1px solid black;
border-collapse: collapse;
padding: 8px;
}
</style>
</head>
<body>
<table>
<thead>
<tr>
<th>machine</th>
<th>status</th>
<th>timesinceLastCheck 3</th>
<th>Original HTML from Email (Inner Table)</th>
</tr>
</thead>
<tbody>
<tr>
<td>Row 1, Cell 1</td>
<td>Row 1, Cell 2</td>
<td>Row 1, Cell 3</td>
<td>
<table>
<thead>
<tr>
<th>Inner Table Header 1</th>
<th>Inner Table Header 2</th>
</tr>
</thead>
<tbody>
<tr>
<td>Row 1, Inner Cell 1</td>
<td>Row 1, Inner Cell 2</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>Row 2, Cell 1</td>
<td>Row 2, Cell 2</td>
<td>Row 2, Cell 3</td>
<td>
<table>
<thead>
<tr>
<th>Inner Table Header 1</th>
<th>Inner Table Header 2</th>
</tr>
</thead>
<tbody>
<tr>
<td>Row 2, Inner Cell 1</td>
<td>Row 2, Inner Cell 2</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>Row 3, Cell 1</td>
<td>Row 3, Cell 2</td>
<td>Row 3, Cell 3</td>
<td>
<table>
<thead>
<tr>
<th>Inner Table Header 1</th>
<th>Inner Table Header 2</th>
</tr>
</thead>
<tbody>
<tr>
<td>Row 3, Inner Cell 1</td>
<td>Row 3, Inner Cell 2</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>Row 4, Cell 1</td>
<td>Row 4, Cell 2</td>
<td>Row 4, Cell 3</td>
<td>
<table>
<thead>
<tr>
<th>Inner Table Header 1</th>
<th>Inner Table Header 2</th>
</tr>
</thead>
<tbody>
<tr>
<td>Row 4, Inner Cell 1</td>
<td>Row 4, Inner Cell 2</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</body>
</html>
that is my search/filter function
function searchTable() {
var input, filter, table, tr, td, i, txtValue;
input = document.getElementById("searchInput");
filter = input.value.toUpperCase();
table = document.getElementById("machineTable");
tr = table.getElementsByTagName("tr");
// Get selected radio button value for filter
var selectedFilter = document.querySelector('input[name="filter"]:checked').value.toUpperCase();
// Get selected radio button value for days
var selectedDays = document.querySelector('input[name="days"]:checked').value;
// Loop through all table rows
for (i = 0; i < tr.length; i++) {
if (i !== 0) { // Check if the row is not the first row (header row)
td = tr[i].getElementsByTagName("td");
alert("länge der tr")
alert (tr.length)
var matchFound = false;
// Loop through all table columns
//td.length -1 entfernt
for (var j = 0; j < 9 ; j++) {
var cell = td[j];
if (cell) {
txtValue = cell.textContent || cell.innerText;
// Check if the cell text contains the filter text, matches the selected filter, and days condition
alert(td[i]);
alert(i);
if ((selectedFilter === "ALL" || td[4].innerText.toUpperCase() === selectedFilter) &&
txtValue.toUpperCase().indexOf(filter) > -1 &&
(selectedDays === "ALL" || parseInt(td[7].innerText) >= parseInt(selectedDays))) {
matchFound = true;
break;
}
}
}
// Hide or show the row based on match
if (matchFound) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}
Edit: the idea of using the querySelectorAll() from James was very good
i then used the solution given in the comments by CarstenMassmann:
let tr = table.querySelectorAll(":scope > tbody > tr");
this gives me the correct number of rows, in the innerloop i just iterate every tr with the numberOfColumns because i still get too much td elements, and i did not figure it out yet how
but with the static numberOfColumns it works for me, but my search function will still search through the inner HTML what can cause performance issues
2
Answers
You can get only tds which are direct children of the main table like this
let tr = table.querySelectorAll(":scope > tbody > tr > td");
Instead of writing further comments I decided to demonstrate the whole filtering mechanism here:
I have used a few slightly more advanced concepts here too:
destructuring assignment:
[filt,days,tbody]=["input","select","#machineTable tbody"].map(sel=>document.querySelector(sel))
withArray.map()
(see map)Is an easy way to run a loop and assign the results to an array of constants or variables
the RegExp class offers a possibility of comparing case insensitively when using
"i"
as a second argumentI used
tr.children
(see children property) here to get an HTMLcollection of elements. This is an alternative to usingtr.querySelectorAll(":scope td")
which would have returned a NodeList. Both lists are slightly different and are not of type "Array"the
...
("spread syntax") is then used to convert thetr.children
collection into a proper array.