Reputation: 57
Each column filter, filters its own column, but when trying to filter another column, previous column filters are not remembered.
For example, in the given table: If I search "Basketball" as the sport, then want to narrow my results and search for a specific team in the "Team" column, my results from the "Sport" column are no longer included because the table has reset.
I want to make this usable regardless of the input fields and corresponding columns. So I could use it on multiple tables if need be. That is why I used:
// if data-label matches input name - run
if(cells[j].getAttribute('data-label').match(inputName)){
// do stuff
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Filter Table by Column</title>
<link rel="stylesheet" href="css/style.css
">
</head>
<body>
<table>
<thead>
<tr>
<td><input type="text" name="Player" placeholder="Player... "></td>
<td><input type="text" name="Sport" placeholder="Sport..."></td>
<td><input type="text" name="Team" placeholder="Team..."></td>
</tr>
</thead>
<tbody>
<tr>
<td data-label="Player">Michael Jordan</td>
<td data-label="Sport">Basketball</td>
<td data-label="Team">Chicago Bulls</td>
</tr>
<tr>
<td data-label="Player">Kobe Bryant</td>
<td data-label="Sport">Basketball</td>
<td data-label="Team">LA Lakers</td>
</tr>
<tr>
<td data-label="Player">Brett Favre</td>
<td data-label="Sport">Football</td>
<td data-label="Team">Greenbay Packers</td>
</tr>
<tr>
<td data-label="Player">Babe Ruth</td>
<td data-label="Sport">Baseball</td>
<td data-label="Team">New York Yankees</td>
</tr>
<tr>
<td data-label="Player">Tom Brady</td>
<td data-label="Sport">Football</td>
<td data-label="Team">New England Patriots</td>
</tr>
<tr>
<td data-label="Player">LeBron James</td>
<td data-label="Sport">Basketball</td>
<td data-label="Team">LA Lakers</td>
</tr>
<tr>
<td data-label="Player">Steph Curry</td>
<td data-label="Sport">Basketball</td>
<td data-label="Team">Golden State Warriors</td>
</tr>
<tr>
<td data-label="Player">Jose Berrios</td>
<td data-label="Sport">Baseball</td>
<td data-label="Team">Minnesota Twins</td>
</tr>
<tr>
<td data-label="Player">Kirby Pucket</td>
<td data-label="Sport">Baseball</td>
<td data-label="Team">Minnesota Twins</td>
</tr>
<tr>
<td data-label="Player">Zach Parise</td>
<td data-label="Sport">Hockey</td>
<td data-label="Team">Minnesota Wild</td>
</tr>
<tr>
<td data-label="Player">Jason Zucker</td>
<td data-label="Sport">Hockey</td>
<td data-label="Team">Minnesota Wild</td>
</tr>
</tbody>
</table>
<script src="js/main.js"></script>
</body>
</html>
main.js
// Listen to all clicks on the document
document.addEventListener('keyup', function(e){
// if event doesn't match
if(!e.target.matches('input[type="text"]')) return;
// otherwise run
filterTable(e);
}, false);
// filter results
function filterTable(e){
let inputName = e.target.name;
let filter = e.target.value.toUpperCase();
let rows = document.querySelector('table tbody').rows;
// get each row
for(let i = 0; i < rows.length; i++){
// loop through each cell
let cells = rows[i].cells;
for(j = 0; j < cells.length; j++){
let rowContent = cells[j].textContent;
// if data-label matches input name - run
if(cells[j].getAttribute('data-label').match(inputName)){
// if rowContent inlcudes input - run
if(rowContent.toUpperCase().includes(filter)){
// show row
rows[i].style.display = "";
} else {
// hide row
rows[i].style.display = "none";
}
}
}
}
}
style.css
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
height: 100%;
line-height: 1.5;
}
input {
padding: 8px;
border: 0;
border-bottom: 1px solid #ccc;
width: 100%;
}
input:focus {
outline: none;
}
table {
border-collapse: collapse;
width: 100%;
margin-top: 20px;
padding: 8px;
}
table td {
padding: 8px;
}
table tbody tr:hover {
background: #999;
}
Upvotes: 2
Views: 3380
Reputation: 22876
Can be simplified with array of filters :
function filterTable() {
const query = q => document.querySelectorAll(q);
const filters = [...query('th input')].map(e => new RegExp(e.value, 'i'));
query('tbody tr').forEach(row => row.style.display =
filters.every((f, i) => f.test(row.cells[i].textContent)) ? '' : 'none');
}
<table>
<thead>
<tr>
<th><input onkeyup="filterTable()" placeholder="Player... "></th>
<th><input onkeyup="filterTable()" placeholder="Sport..."></th>
<th><input onkeyup="filterTable()" placeholder="Team..."></th>
</tr>
</thead>
<tbody>
<tr><td> Michael Jordan </td><td> Basketball </td><td> Chicago Bulls </td></tr>
<tr><td> Kobe Bryant </td><td> Basketball </td><td> LA Lakers </td></tr>
<tr><td> Brett Favre </td><td> Football </td><td> Greenbay Packers </td></tr>
<tr><td> Babe Ruth </td><td> Baseball </td><td> New York Yankees </td></tr>
<tr><td> Tom Brady </td><td> Football </td><td> New England Patriots </td></tr>
<tr><td> LeBron James </td><td> Basketball </td><td> LA Lakers </td></tr>
<tr><td> Steph Curry </td><td> Basketball </td><td> Golden State Warriors </td></tr>
<tr><td> Jose Berrios </td><td> Baseball </td><td> Minnesota Twins </td></tr>
<tr><td> Kirby Pucket </td><td> Baseball </td><td> Minnesota Twins </td></tr>
<tr><td> Zach Parise </td><td> Hockey </td><td> Minnesota Wild </td></tr>
<tr><td> Jason Zucker </td><td> Hockey </td><td> Minnesota Wild </td></tr>
</tbody>
</table>
Upvotes: 4
Reputation: 999
I use a object to store the different queries and then check each one when the input of any one change.
You can find a working demo here: https://codesandbox.io/s/suspicious-flower-80c8d
my js looks like this:
const queries = {};
const inputs = [...document.querySelectorAll("input")];
for (let input of inputs) {
input.addEventListener("input", e => {
const name = input.name;
queries[name] = input.value;
filterTable();
});
}
function filterRow(row, query, label) {
if (query) {
const text = row.querySelector('td[data-label="' + label + '"]').innerText;
if (text.toLowerCase().indexOf(query.toLowerCase()) < 0) {
row.style.display = "none";
}
}
}
function filterTable() {
document.querySelectorAll("tr").forEach((row, index) => {
if (index === 0) {
return;
}
row.style.display = "table-row";
for (let key in queries) {
filterRow(row, queries[key], key);
}
});
}
Upvotes: 0
Reputation: 3409
You can add an event listener on when the user starts to type and then match the input with the element's value. For all the td
elements, check for those which matches to the string input using .includes
and then change the visibility of that element to hidden if it doesn't match if it does then make it visible.
Now to filter out Teams and Sport, just do the same for the next element and the previous because they are consecutive.
document.getElementsByName("Player")[0].onkeyup = function() {
let value = this.value
Array.from(document.querySelectorAll('td[data-label="Player"]')).forEach((ele) => {
if (value != '') {
ele.style.visibility = "visible" // first display all the elements then decide what to display and what not to.
if (ele.innerHTML.toLowerCase().includes(value.toLowerCase())) { // match the lower cased value so "B == b"
ele.style.visibility = "visible"
} else {
ele.style.visibility = "hidden"
ele.nextElementSibling.style.visibility = "hidden" // the teams
ele.nextElementSibling.nextElementSibling.style.visibility = "hidden" // the Sport
}
} else {
ele.style.visibility = "visible"
ele.nextElementSibling.style.visibility = "visible"
ele.nextElementSibling.nextElementSibling.style.visibility = "visible"
}
})
}
document.getElementsByName("Sport")[0].onkeyup = function() {
let value = this.value
Array.from(document.querySelectorAll('td[data-label="Sport"]')).forEach((ele) => {
if (value != '') {
ele.style.visibility = "visible"
if (ele.innerHTML.toLowerCase().includes(value.toLowerCase())) {
ele.style.visibility = "visible"
ele.previousElementSibling.style.visibility = "visible"
} else {
ele.style.visibility = "hidden"
ele.previousElementSibling.style.visibility = "hidden"
}
} else {
ele.style.visibility = "visible"
ele.previousElementSibling.style.visibility = "visible"
}
})
}
document.getElementsByName("Team")[0].onkeyup = function() {
let value = this.value
Array.from(document.querySelectorAll('td[data-label="Team"]')).forEach((ele) => {
if (value != '') {
ele.style.visibility = "visible"
if (ele.innerHTML.includes(value)) {
ele.style.visibility = "visible"
ele.previousElementSibling.style.visibility = "visible"
ele.previousElementSibling.previousElementSibling.style.visibility = "visible"
} else {
ele.style.visibility = "hidden"
ele.previousElementSibling.style.visibility = "hidden"
ele.previousElementSibling.previousElementSibling.style.visibility = "hidden"
}
} else {
ele.style.visibility = "visible"
ele.previousElementSibling.style.visibility = "visible"
ele.previousElementSibling.previousElementSibling.style.visibility = "visible"
}
})
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
height: 100%;
line-height: 1.5;
}
input {
padding: 8px;
border: 0;
border-bottom: 1px solid #ccc;
width: 100%;
}
input:focus {
outline: none;
}
table {
border-collapse: collapse;
width: 100%;
margin-top: 20px;
padding: 8px;
}
table td {
padding: 8px;
}
table tbody tr:hover {
background: #999;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Filter Table by Column</title>
</head>
<body>
<table>
<thead>
<tr>
<td><input type="text" name="Player" placeholder="Player... "></td>
<td><input type="text" name="Sport" placeholder="Sport..."></td>
<td><input type="text" name="Team" placeholder="Team..."></td>
</tr>
</thead>
<tbody>
<tr>
<td data-label="Player">Michael Jordan</td>
<td data-label="Sport">Basketball</td>
<td data-label="Team">Chicago Bulls</td>
</tr>
<tr>
<td data-label="Player">Kobe Bryant</td>
<td data-label="Sport">Basketball</td>
<td data-label="Team">LA Lakers</td>
</tr>
<tr>
<td data-label="Player">Brett Favre</td>
<td data-label="Sport">Football</td>
<td data-label="Team">Greenbay Packers</td>
</tr>
<tr>
<td data-label="Player">Babe Ruth</td>
<td data-label="Sport">Baseball</td>
<td data-label="Team">New York Yankees</td>
</tr>
<tr>
<td data-label="Player">Tom Brady</td>
<td data-label="Sport">Football</td>
<td data-label="Team">New England Patriots</td>
</tr>
<tr>
<td data-label="Player">LeBron James</td>
<td data-label="Sport">Basketball</td>
<td data-label="Team">LA Lakers</td>
</tr>
<tr>
<td data-label="Player">Steph Curry</td>
<td data-label="Sport">Basketball</td>
<td data-label="Team">Golden State Warriors</td>
</tr>
<tr>
<td data-label="Player">Jose Berrios</td>
<td data-label="Sport">Baseball</td>
<td data-label="Team">Minnesota Twins</td>
</tr>
<tr>
<td data-label="Player">Kirby Pucket</td>
<td data-label="Sport">Baseball</td>
<td data-label="Team">Minnesota Twins</td>
</tr>
<tr>
<td data-label="Player">Zach Parise</td>
<td data-label="Sport">Hockey</td>
<td data-label="Team">Minnesota Wild</td>
</tr>
<tr>
<td data-label="Player">Jason Zucker</td>
<td data-label="Sport">Hockey</td>
<td data-label="Team">Minnesota Wild</td>
</tr>
</tbody>
</table>
</body>
</html>
Upvotes: 0