2

I am trying to make filter that will filter based on multiple inputs. One input will filter in one column.

My JavaScript & code:

function myFunction(column, input) {
  var filter, table, tr, td, i, txtValue;
  filter = input.value.toUpperCase();
  table = document.getElementById("myTable");
  tr = table.getElementsByTagName("tr");
  for (i = 0; i < tr.length; i++) {
    td = tr[i].getElementsByTagName("td")[column];
    if (td) {
      txtValue = td.textContent || td.innerText;
      if (txtValue.toUpperCase().indexOf(filter) > -1) {
        tr[i].style.display = "";
      } else {
        tr[i].style.display = "none";
      }
    }
  }
}
<div class="row">
<input class="font-15 w-180-px" onkeydown="myFunction(0, this)" type="text">
 <label class="font-18"> Input 1 </label>
<br>

 <input class="font-15 w-180-px" onkeydown="myFunction(1, this)" type="text">
   <label class="font-18"> Input 2 </label>
            <br>

<input class="font-15 w-180-px" onkeydown="myFunction(2, this)" type="text">
<label class="font-18"> Input 3 </label>
            <br>

<input class="font-15 w-180-px" onkeydown="myFunction(3, this)" type="text">
<label class="font-18"> Input 4 </label>
            <br>

<input class="font-15 w-180-px" onkeydown="myFunction(4, this)" type="text">
<label class="font-18"> Input 5 </label>
            <br>

<input class="font-15 w-180-px" onkeydown="myFunction(5, this)" type="text">
<label class="font-18"> Input 6 </label>
            <br>
</div>


<table id="myTable">
  <tr class="header">
    <th style="width:20%;">1</th>
    <th style="width:20%;">2</th>
    <th style="width:20%;">3</th>
    <th style="width:20%;">4</th>
    <th style="width:20%;">5</th>
    <th style="width:20%;">6</th>
  </tr>
  <tr>
    <td>Some 1 - a</td>
    <td>Some 2 - a</td>
    <td>Some 3 - a</td>
    <td>Some 4 - a</td>
    <td>Some 5 - a</td>
    <td>Some 6 - a</td>
  </tr>
  <tr>
    <td>Some 1 - b</td>
    <td>Some 2 - b</td>
    <td>Some 3 - b</td>
    <td>Some 4 - b</td>
    <td>Some 5 - b</td>
    <td>Some 6 - b</td>
  </tr>
  <tr>
    <td>Some 1 - c</td>
    <td>Some 2 - c</td>
    <td>Some 3 - c</td>
    <td>Some 4 - c</td>
    <td>Some 5 - c</td>
    <td>Some 6 - c</td>
  </tr>
  <tr>
    <td>Some 1 - d</td>
    <td>Some 2 - d</td>
    <td>Some 3 - d</td>
    <td>Some 4 - d</td>
    <td>Some 5 - d</td>
    <td>Some 6 - d</td>
  </tr>
</table>

So basically - now I enter value in Input 1 and it filters table corectly but then I enter value into Input 2 and it filters value only for second column of table. I want to enter value into Input 1 and Input 2 and it will filter row where Input 1 and Input 2 values are contained. Thanks for any help.

btw. I dont have problem with using JQuery.

2 Answers 2

2

function myFunction(column, input) {
            var filter, table, tr, td, i, txtValue;
            filter = input.value.toUpperCase();
            console.log(filter);
            table = document.getElementById("myTable");
            tr = table.getElementsByTagName("tr");
            for (i = 0; i < tr.length; i++) {
                td = tr[i].getElementsByTagName("td")[column];
                if (td) {
                    txtValue = td.textContent || td.innerText;
                    console.log(filter, txtValue.toUpperCase().indexOf(filter));
                    if (txtValue.toUpperCase().indexOf(filter) > -1) {
                        if(tr[i].style.display != "none") // if something has been hidden by previous filter, we don't want to show it
                          tr[i].style.display = "";
                    } else {
                        tr[i].style.display = "none";
                    }
                }
            }
        }
<div class="row">
    
    <input class="font-15 w-180-px" onchange="myFunction(0, this)" type="text"><label class="font-18"> Input 1 </label><br>
   <input class="font-15 w-180-px" onchange="myFunction(1, this)" type="text"> <label class="font-18"> Input 2 </label>
                <br>
    

    <input class="font-15 w-180-px" onchange="myFunction(2, this)" type="text"><label class="font-18"> Input 3 </label>
                <br>
</div>

<table id="myTable">
    <tr class="header">
        <th style="width:20%;">1</th>
        <th style="width:20%;">2</th>
        <th style="width:20%;">3</th>
        <th style="width:20%;">4</th>
        <th style="width:20%;">5</th>
        <th style="width:20%;">6</th>
    </tr>
    <tr>
        <td>Some 1 - a</td>
        <td>Some 2 - a</td>
        <td>Some 3 - a</td>
        <td>Some 4 - a</td>
        <td>Some 5 - a</td>
        <td>Some 6 - a</td>
    </tr>
    <tr>
        <td>Some 1 - b</td>
        <td>Some 2 - b</td>
        <td>Some 3 - b</td>
        <td>Some 4 - b</td>
        <td>Some 5 - b</td>
        <td>Some 6 - b</td>
    </tr>
    <tr>
        <td>Some 1 - c</td>
        <td>Some 2 - c</td>
        <td>Some 3 - c</td>
        <td>Some 4 - c</td>
        <td>Some 5 - c</td>
        <td>Some 6 - c</td>
    </tr>
    <tr>
        <td>Some 1 - d</td>
        <td>Some 2 - d</td>
        <td>Some 3 - d</td>
        <td>Some 4 - d</td>
        <td>Some 5 - d</td>
        <td>Some 6 - d</td>
    </tr>
</table>

Here's a naive solution - before setting display to empty string, make sure that previous filter didn't hide particular row. You still have to take care of 'resetting' the filters, though.

I'd go with following solution (of course, to be refactored):

var filters = ["", "", ""];

function applyNewFilters() {
  console.log(filters);
  var rows = $('#myTable').find('tr');
  for(var i = 1; i < rows.length; i++) {
    var row = $(rows[i]); // we're re-applying all filters anyway
    row.show();
  }
  for(var i = 1; i < rows.length; i++) {
    var row = $(rows[i]);
    for(var f = 0; f < filters.length; f++) {
      //column is going to be equal to f
      var col = $(row.find('td')[f]).text();
      console.log(col);
      if(col.indexOf(filters[f]) < 0) {
        row.hide();
      }
    }
  }
}

$('.filter-input').on('change', function() {
  var $modifiedInput = $(this);
  console.log($modifiedInput.val());
  var column = $modifiedInput.attr('data-col');
    filters[column] = $modifiedInput.val();
    applyNewFilters();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="row">
        
        <input class="font-15 w-180-px filter-input" data-col="0" type="text"><label class="font-18"> Input 1 </label><br>
       <input class="font-15 w-180-px filter-input" data-col="1"  type="text"> <label class="font-18"> Input 2 </label>
                    <br>
        

        <input class="font-15 w-180-px filter-input"  data-col="2" type="text"><label class="font-18"> Input 3 </label>
                    <br>
    </div>

    <table id="myTable">
        <tr class="header">
            <th style="width:20%;">1</th>
            <th style="width:20%;">2</th>
            <th style="width:20%;">3</th>
            <th style="width:20%;">4</th>
            <th style="width:20%;">5</th>
            <th style="width:20%;">6</th>
        </tr>
        <tr>
            <td>Some 1 - a</td>
            <td>Some 2 - b</td>
            <td>Some 3 - a</td>
            <td>Some 4 - a</td>
            <td>Some 5 - a</td>
            <td>Some 6 - a</td>
        </tr>
        <tr>
            <td>Some 1 - b</td>
            <td>Some 2 - b</td>
            <td>Some 3 - b</td>
            <td>Some 4 - b</td>
            <td>Some 5 - b</td>
            <td>Some 6 - b</td>
        </tr>
        <tr>
            <td>Some 1 - c</td>
            <td>Some 2 - c</td>
            <td>Some 3 - c</td>
            <td>Some 4 - c</td>
            <td>Some 5 - c</td>
            <td>Some 6 - c</td>
        </tr>
        <tr>
            <td>Some 1 - d</td>
            <td>Some 2 - d</td>
            <td>Some 3 - d</td>
            <td>Some 4 - d</td>
            <td>Some 5 - d</td>
            <td>Some 6 - d</td>
        </tr>
    </table>

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

3 Comments

Wow, thanks, that's really clever and easy solution. Thank you very much.
That's not really clever, but working :) I advise you to refactor it a bit, though - change these archaic 'for' loops into forEach loops etc. But it's up to you, of course.
It's very good anyways because I was unable to do something like this for like day and half and you came up with fairly easy solution :). Thank you so much
0

Try like below. Use onkeyup instead of onkeydown. Use myFunction without parameter because we need to apply filter from all inputs.

Add id to each input and retrieve their values in filters array. Added comments for explanation of logic.

Try it below.

function myFunction() {
  var tr, td, i, txtValue;
  table = document.getElementById("myTable");
  tr = table.getElementsByTagName("tr");

  // get all filter values.
  // use isApplyFilter to get whether any input is provided for filter or not.
  let filters = [],
    isApplyFilter = false;
  for (i = 0; i < 6; i++) {
    filters.push($('#input' + (i + 1)).val().toUpperCase().trim());
    isApplyFilter = isApplyFilter || !!filters[i];
  }

  // loop over all tr except 1st one because it is header.
  for (i = 1; i < tr.length; i++) {

    // if isApplyFilter = false then show all rows
    if (!isApplyFilter) {
      tr[i].style.display = "";
      continue;
    }

    // by default hide row
    tr[i].style.display = "none";

    // loop over all columns and respective filter value
    for (j = 0; j < 6; j++) {
      // get column
      td = tr[i].getElementsByTagName("td")[j];

      // if filter has value then only check for condition
      if (filters[j] && td) {
        txtValue = td.textContent || td.innerText;
        // on satisfied condition show row and break inner loop
        if (txtValue.toUpperCase().indexOf(filters[j]) > -1) {
          tr[i].style.display = "";
          break;
        }
      }
    }
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
<div class="row">
  <label class="font-18"> Input 1 </label>
  <br>
  <input id='input1' class="font-15 w-180-px" onkeyup="myFunction()" type="text">

  <label class="font-18"> Input 2 </label>
  <br>
  <input id='input2' class="font-15 w-180-px" onkeyup="myFunction()" type="text">

  <label class="font-18"> Input 3 </label>
  <br>
  <input id='input3' class="font-15 w-180-px" onkeyup="myFunction()" type="text">

  <label class="font-18"> Input 4 </label>
  <br>
  <input id='input4' class="font-15 w-180-px" onkeyup="myFunction()" type="text">

  <label class="font-18"> Input 5 </label>
  <br>
  <input id='input5' class="font-15 w-180-px" onkeyup="myFunction()" type="text">

  <label class="font-18"> Input 6 </label>
  <br>
  <input id='input6' class="font-15 w-180-px" onkeyup="myFunction()" type="text">
</div>

<table id="myTable">
  <tr class="header">
    <th style="width:20%;">1</th>
    <th style="width:20%;">2</th>
    <th style="width:20%;">3</th>
    <th style="width:20%;">4</th>
    <th style="width:20%;">5</th>
    <th style="width:20%;">6</th>
  </tr>
  <tr>
    <td>Some 1 - a</td>
    <td>Some 2 - a</td>
    <td>Some 3 - a</td>
    <td>Some 4 - a</td>
    <td>Some 5 - a</td>
    <td>Some 6 - a</td>
  </tr>
  <tr>
    <td>Some 1 - b</td>
    <td>Some 2 - b</td>
    <td>Some 3 - b</td>
    <td>Some 4 - b</td>
    <td>Some 5 - b</td>
    <td>Some 6 - b</td>
  </tr>
  <tr>
    <td>Some 1 - c</td>
    <td>Some 2 - c</td>
    <td>Some 3 - c</td>
    <td>Some 4 - c</td>
    <td>Some 5 - c</td>
    <td>Some 6 - c</td>
  </tr>
  <tr>
    <td>Some 1 - d</td>
    <td>Some 2 - d</td>
    <td>Some 3 - d</td>
    <td>Some 4 - d</td>
    <td>Some 5 - d</td>
    <td>Some 6 - d</td>
  </tr>
</table>

Comments

Your Answer

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