I have a table with six columns containing approximately 7,000 entries. Currently, the table is filtered by six separate input text boxes, each with its own JavaScript function. Each function targets a specific column using code like:
td = tr[i].getElementsByTagName("td")[0];
td = tr[i].getElementsByTagName("td")[1];
td = tr[i].getElementsByTagName("td")[2];
Due to having multiple scripts on the page, it becomes unresponsive and takes a long time to load.
To solve this performance issue, is it possible to filter the table with only one input box instead of six, but with a dropdown/select box to choose which column (td[0]
, td[1]
, td[2]
, etc.) to filter?
function filterTable() {
var input, filter, table, tr, td, i, txtValue;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
table = document.getElementById("myTable");
tr = table.getElementsByTagName("tr");
rowsFound = [];
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[4];
if (td) {
txtValue = td.textContent || td.innerText;
if (txtValue.toUpperCase().indexOf(filter) == 0) {
tr[i].style.display = "";
rowsFound.push(1);
} else {
tr[i].style.display = "none";
}
}
}
}
<span style="float:left">Total/Searched:</span>
<div id="statistic" style="float:left"></div>
<br><br><br>
<input type="text" id="myInput" onkeyup="filterTable()" onClick="filterTable()" placeholder="Search...">
<table id="myTable">
<thead>
<tr>
<th>Name</th>
<th>Country</th>
<th>City</th>
<th>Street</th>
<th>House No</th>
<th>Neighbour</th>
</tr>
</thead>
<tbody>
<tr>
<td>Mario Resende</td>
<td>Argentina</td>
<td>Buenos Aires</td>
<td>Belgrano Calle</td>
<td>2:3</td>
<td>Cristina Rodriguez</td>
</tr>
<tr>
<td>Philips Douglas</td>
<td>United Kingdom</td>
<td>London</td>
<td>Oxford Avenue</td>
<td>17:25</td>
<td>Sophie Loren</td>
</tr>
<tr>
<td>Ramesh Bugatapa</td>
<td>India</td>
<td>New Delhi</td>
<td>Golochand road</td>
<td>1:2</td>
<td>Kiran Johr</td>
</tr>
</tbody>
</table>
I think you can achieve better performance by using the property hierarchy of HTML tables.
for (let row of myTable.tBodies[0].rows)
{ ... }
And to test this, also avoid using string manipulation functions. The regular expression system is optimized for this.
rExp.test(row.cells[cIndex].textContent)
Otherwise, I suggest clicking directly on the column header to launch a filter (rather than using a select with the same information)
The code may look like this:
const
txt2search = document.querySelector('#txt-2-search')
, searchResult = document.querySelector('#search-result')
, myTable = document.querySelector('#my-table')
, searchInfo = { cIndex: null, rExp: null, count:0, rFound:0 }
;
searchResult.textContent
= searchInfo.count
= myTable.tBodies[0].rows.length
;
function showALL_elements() {
myTable.tBodies[0].querySelectorAll('tr.noDisplay').forEach( TR =>
{
TR.classList.remove('noDisplay');
})
searchResult.textContent = searchInfo.count;
}
myTable.tHead.onclick = ({target:xTH}) => {
if (!xTH.matches('th')) // this is a bad click...!
return
;
if (xTH.classList.toggle('cFilter')) // this a go-to-do filter
{
if (searchInfo.cIndex !== null)
xTH.closest('tr').cells[searchInfo.cIndex].classList.remove('cFilter')
;
searchInfo.cIndex = xTH.cellIndex;
// Normally you have to be sure of the validity of the filtering criteria
// (no empty string, no special characters, etc.)
searchInfo.rFound = searchInfo.count;
searchInfo.rExp = new RegExp(`^${txt2search.value.trim()}`, 'i');
for (let row of myTable.tBodies[0].rows)
{
if ( row.classList.toggle
( 'noDisplay'
, !searchInfo.rExp.test(row.cells[searchInfo.cIndex].textContent)
) )
searchInfo.rFound--
;
} // end loop for
searchResult.textContent = `${searchInfo.rFound} / ${searchInfo.count}`;
}
else
{
searchInfo.cIndex = null;
showALL_elements();
}
}
* {
margin : 0;
padding : 0;
}
body {
background : lavender;
font-family : Geneva, sans-serif;
font-size : 16px;
}
table {
border-collapse : separate;
border-spacing : 1px;
background : darkblue;
margin : 1em;
}
td,th { padding : .2em .8em; }
td { background : whitesmoke; }
th { background : #9bbad8; cursor : zoom-in; }
th.cFilter { background : orange; }
.noDisplay { display : none; }
caption {
text-align : left;
padding : .4rem;
font-size : 1.4rem;
background : #a0dbdd;
& input {
font-size : 1.2rem;
}
& #search-result {
float : right;
font-size : .9rem;
}
}
<table id="my-table">
<caption>
Find :
<input type="text" id="txt-2-search" placeholder="then, select a column..." />
<span id="search-result">0</span>
</caption>
<thead>
<tr>
<th>Name</th>
<th>Country</th>
<th>City</th>
<th>Street</th>
<th>House No</th>
<th>Neighbour</th>
</tr>
</thead>
<tbody>
<tr>
<td>Mario Resende</td>
<td>Argentina</td>
<td>Buenos Aires</td>
<td>Belgrano Calle</td>
<td>2:3</td>
<td>Cristina Rodriguez</td>
</tr>
<tr>
<td>Philips Douglas</td>
<td>United Kingdom</td>
<td>London</td>
<td>Oxford Avenue</td>
<td>17:25</td>
<td>Sophie Loren</td>
</tr>
<tr>
<td>Ramesh Bugatapa</td>
<td>India</td>
<td>New Delhi</td>
<td>Golochand road</td>
<td>1:2</td>
<td>Kiran Johr</td>
</tr>
</tbody>
</table>