Andreas Gartmyr
Andreas Gartmyr

Reputation: 43

How to filter a table based on a simple text input

I have been struggling with trying to filter a table based on a simple text input. It works on the first column but I also want the user to be able to filter by the second column. So I tried to add the var ts but that didn't. Any help would be much appreciated :-)

function search () {
var field = document.getElementById("searchField");
var filter = field.value.toUpperCase();
var table = document.getElementById('table');
var tr = table.getElementsByTagName('tr');
var i;
var txtValue;
var td;
var ts;
if (filter.length > 0)
{
    for (i = 0; i < tr.length; i++)
    {
        td = tr[i].getElementsByTagName("td")[0];
        ts = tr[i].getElementsByTagName("td")[1];
        if (td)
        {
            txtValue = td.textContent || td.innerText || ts.textContent || ts.innerText;
            if (txtValue.toUpperCase().indexOf(filter) > -1)
            {
                tr[i].style.display = "";
            }
            else
            {
                tr[i].style.display = "none";
            }
        }
    }
}

}

Here's part of the php:

$get_persons = $connection->prepare('SELECT first_name, last_name FROM persons WHERE status = :status ORDER BY first_name ASC');
    $get_persons->execute([status=>'success']);
    echo '
        <input type="text" class="search-field" id="searchField" onkeyup="search()" placeholder="'.$searchPlaceholder.'" />
        <table id="table" class="start-list-table">
            <thead>
                <tr class="start-list-tr">
                    <th scope="col">'.$titleFirstName.'</th>
                    <th scope="col">'.$titleLastName.'</th>
                </tr>
            </thead>
            <tbody>
    ';
    $persons = $get_persons->fetchAll();
    foreach($persons as $person){
        echo '
            <tr class="start-list-tr">
                <td data-label="'.$titleFirstName.'">'.$person->first_name'</td>
                <td data-label="'.$titleLastName.'">'.$person->last_name.'</td>
            </tr>';
    }
    echo '</tbody>
    </table>';

Upvotes: 0

Views: 1243

Answers (3)

ylc395
ylc395

Reputation: 93

txtValue = td.textContent || td.innerText || ts.textContent || ts.innerText;

This statement says txtValue will be td's inner text if td has inner text, so in those cases you're still filter rows by column1 not column2. Use this:

textValue = [td.textContent || td.innerText, ts.textContent || ts.innerText];

if (txtValue.some(txt => txt.toUpperCase().indexOf(filter) > -1))
{
    tr[i].style.display = "";
}
else
{
    tr[i].style.display = "none";
}

Upvotes: 0

Andreas Gartmyr
Andreas Gartmyr

Reputation: 43

@srikanthreddy pointed me to this thread which solved my issue in a much nicer way. Thanks!

Upvotes: 1

Kalimah
Kalimah

Reputation: 11447

You have this line var table = document.getElementById('table'); which I doubt that table is an id. It is better to use querySelector() and querySelectorAll() if you don not require live nodes.

Here is an example with mock table data:

function search(field) {
  var filter = field.value.toUpperCase();
  var table = document.querySelector('table');
  var tr = table.querySelectorAll('tr');
  var i;
  var txtValue;
  var td;
  var ts;

  if (filter.length > 0) {
    for (i = 0; i < tr.length; i++) {
      td = tr[i].querySelector("td:first-child");
      ts = tr[i].querySelector("td:nth-child(2)");
      if (td) {

        txtValue = td.textContent || td.innerText || ts.textContent || ts.innerText;
        if (txtValue.toUpperCase().indexOf(filter) > -1) {
          tr[i].style.display = "";
        } else {
          tr[i].style.display = "none";
        }
      }
    }
  }
}
<input type='text' id='searchField' oninput='search(this)'>
<table>
  <tr>
    <th>Company</th>
    <th>Contact</th>
    <th>Country</th>
  </tr>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td>Maria Anders</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Centro comercial Moctezuma</td>
    <td>Francisco Chang</td>
    <td>Mexico</td>
  </tr>
  <tr>
    <td>Ernst Handel</td>
    <td>Roland Mendel</td>
    <td>Austria</td>
  </tr>
  <tr>
    <td>Island Trading</td>
    <td>Helen Bennett</td>
    <td>UK</td>
  </tr>
  <tr>
    <td>Laughing Bacchus Winecellars</td>
    <td>Yoshi Tannamuri</td>
    <td>Canada</td>
  </tr>
  <tr>
    <td>Magazzini Alimentari Riuniti</td>
    <td>Giovanni Rovelli</td>
    <td>Italy</td>
  </tr>
</table>

Upvotes: 0

Related Questions