2

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;
}
1
  • 2
    where is the main.js file? Commented Jul 27, 2019 at 17:30

3 Answers 3

4

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>

Sign up to request clarification or add additional context in comments.

2 Comments

Some really beautiful lines of code, exactly what I needed :) Good job!
Instead of adding a function inline in the html, I did the following in the function constructor() of my project (I used the ES5 function class): this.tableSearch = document.getElementsByName('table-search') And then in events() {}: this.tableSearch.forEach(row => row.addEventListener('keyup', this.searchPets.bind(this)))
0

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>

Comments

0

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);
    }
  });
}

2 Comments

I like your solution but one thing I forgot to mention was I wanted to make this usable regardless of the input fields and corresponding columns. That's why I used if(cells[j].getAttribute('data-label').match(inputName)){ // do stuff }. How might I accomplish this using you method? I tried looping through each input and storing their values as an array but when I try to access the array from the function, the array is not defined.
I update my answer so the example is now genric, it uses the "name" attribute of the input field to match the td data label field

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.