Reputation: 194
I've managed to modify a filterable table JS script to my liking, but I'd like to make it more advanced by making it so I can filter from the remaining filtered items, but I'm not quite sure how to go about it.
Here's a jsfiddle with a similar setup to what I have. The code has gotten significantly more messy since I started messing with it, you might be able to see that I was trying to use the form to ensure we didn't start overwriting our display:none's but then I realised I was a bit over my head.
To clarify, what I'd like to be able to do is to filter say, the name, and then filter that remaining list even further, say, by type.
Is there an efficient way of doing this that I'm completely missing?
Here is the original filter code which was much cleaner before I messed with it:
function filter(term, _id, cellNr){
var suche = term.value.toLowerCase();
var table = document.getElementById(_id);
var ele;
for (var r = 2; r < table.rows.length; r++){
ele = table.rows[r].cells[cellNr].innerHTML.replace(/<[^>]+>/g,"");
if (ele.toLowerCase().indexOf(suche)>=0 )
table.rows[r].style.display = '';
else table.rows[r].style.display = 'none';
}
}
Upvotes: 2
Views: 290
Reputation: 13304
I myself would do it like this:
function filter(_id) {
var table = document.getElementById(_id);
//get all filters.
var getFilters = [table.querySelectorAll("input")[0].value.toLowerCase(),
table.querySelectorAll("input")[1].value.toLowerCase(),
table.querySelectorAll("input")[2].value.toLowerCase()]
for (var r = 2; r < table.rows.length; r++)
{
//strip tags
var el1 = table.rows[r].cells[0].innerHTML.replace(/<[^>]+>/g, "");
var el2 = table.rows[r].cells[1].innerHTML.replace(/<[^>]+>/g, "");
var el3 = table.rows[r].cells[2].innerHTML.replace(/<[^>]+>/g, "");
var search1 = el1.toLowerCase().indexOf(getFilters[0]);
var search2 = el2.toLowerCase().indexOf(getFilters[1]);
var search3 = el3.toLowerCase().indexOf(getFilters[2]);
//test all searches, if found or el = empty display
if ( (search1 >= 0 || el1 == "" ) && (search2 >= 0 || el2 == "" ) && (search3 >= 0 || el3 == "" )) {
table.rows[r].style.display = '';
} else {
table.rows[r].style.display = 'none';
}
}
}
<table id="table">
<tr>
<th>ID</th>
<th>Name</th>
<th>Type</th>
</tr>
<tr>
<td><input placeholder="search" name="filterinput3" onkeyup="filter('table')" type="text" size="3"></input></td>
<td><input placeholder="search" name="filterinput3" onkeyup="filter('table')" type="text" size="3"></input></td>
<td><input placeholder="search" name="filterinput3" onkeyup="filter('table')" type="text" size="3"></input></td>
</tr>
<tr>
<td>1</td>
<td>Bulbasaur</td>
<td>Grass</td>
</tr>
<tr>
<td>4</td>
<td>Charmander</td>
<td>Fire</td>
</tr>
<tr>
<td>7</td>
<td>Squirtle</td>
<td>Water</td>
</tr>
<tr>
<td>1</td>
<td>Bulbasaur</td>
<td>Poison</td>
</tr>
<tr>
<td>6</td>
<td>Charizard</td>
<td>Flying</td>
</tr>
</table>
First, get all input from the input boxes. Store it in an array called getFilters
.
Then:
search the different cells and see if there is a match.
When there is a match (Not -1
) or when the input of that column was empty return true. All three conditions need to return true for a row to show. If not hide the row.
So id
: 1
with the two other inputs empty would yield only bulbasaur with two types.
The real trick here are the conditions:
(search1 >= 0 || el1 == "" ) && (search2 >= 0 || el2 == "" )
They are divided into blocks with the parentheses. The will evaluate seperately into true or false. There are three of those blocks in this example.
This was answered quite a while ago and it deservers a more modern approach:
function filter(_id) {
const table = document.getElementById(_id);
//get all filters
const getFilters = [...table.querySelectorAll("input")].map(element => element.value.toLowerCase());
document.querySelectorAll("tr:nth-child(n+3) > td:first-child").forEach((firstTD) => {
//iterate to the next to td's using nextSibling
const textArray = [firstTD.textContent, firstTD.nextElementSibling.textContent, firstTD.nextElementSibling.nextElementSibling.textContent];
const found = textArray.every((element, index) => {
return element.toLowerCase().indexOf(getFilters[index]) >= 0 || getFilters[index] == "";
});
if (found) {
firstTD.parentElement.style.display = '';
} else {
firstTD.parentElement.style.display = 'none';
}
});
}
<table id="table">
<tr>
<th>ID</th>
<th>Name</th>
<th>Type</th>
</tr>
<tr>
<td><input placeholder="search" name="filterinput3" onkeyup="filter('table')" type="text" size="3"></input>
</td>
<td><input placeholder="search" name="filterinput3" onkeyup="filter('table')" type="text" size="3"></input>
</td>
<td><input placeholder="search" name="filterinput3" onkeyup="filter('table')" type="text" size="3"></input>
</td>
</tr>
<tr>
<td>1</td>
<td>Bulbasaur</td>
<td>Grass</td>
</tr>
<tr>
<td>4</td>
<td>Charmander</td>
<td>Fire</td>
</tr>
<tr>
<td>7</td>
<td>Squirtle</td>
<td>Water</td>
</tr>
<tr>
<td>1</td>
<td>Bulbasaur</td>
<td>Poison</td>
</tr>
<tr>
<td>6</td>
<td>Charizard</td>
<td>Flying</td>
</tr>
</table>
Upvotes: 2