The Web Design Group

... Making the Web accessible to all.

Welcome Guest ( Log In | Register )

 
Reply to this topicStart new topic
> Restrict second table filter to results of first filter?
EdNerd
post May 14 2020, 01:18 PM
Post #1





Group: Members
Posts: 8
Joined: 12-May 20
Member No.: 27,340



I copied code from W3Schools to filter a table for the text in an input and hide all rows that don't match. The function works only on the first column - <td> element [0]. If I change that to element [1], it filters on the second column - only.

I tried to add a second input, copy the function, and rename items as required in the hopes of filtering first on the first column, and then filter any duplicate results on the second column. Unfortunately, that didn't work as planned. The hidden table rows are still there, and the second filter will unhide any previously de-selected rows if the value happens to match the second filter. If I keep going long enough, I do eventually get into my first filter results. But that's too much.

Is there an easy way to restrict the second filter function to looking at only the results of the first filter?
Maybe assign a style or such to the first results and use that as a criteria in the second filter??
Ed

Input and Table CSS:
CODE

<style>

#myInput1 {
  /* background-image: url('/css/searchicon.png'); Add a search icon to input */
  /* background-position: 10px 12px; Position the search icon */
  /* background-repeat: no-repeat; Do not repeat the icon image */
  width: 35%; /* Full-width */
  font-size: 16px; /* Increase font-size */
  padding: 12px 20px 12px 40px; /* Add some padding */
  border: 1px solid #ddd; /* Add a grey border */
  margin-bottom: 12px; /* Add some space below the input */
}

#myInput2 {
  /* background-image: url('/css/searchicon.png'); Add a search icon to input */
  /* background-position: 10px 12px; Position the search icon */
  /* background-repeat: no-repeat; Do not repeat the icon image */
  width: 35%; /* Full-width */
  font-size: 16px; /* Increase font-size */
  padding: 12px 20px 12px 40px; /* Add some padding */
  border: 1px solid #ddd; /* Add a grey border */
  margin-bottom: 12px; /* Add some space below the input */
}

#myTable {
  border-collapse: collapse; /* Collapse borders */
  width: 75%; /* Full-width */
  border: 1px solid #ddd; /* Add a grey border */
  font-size: 18px; /* Increase font-size */
  margin-left: 1em
}

#myTable th, #myTable td {
  text-align: left; /* Left-align text */
  padding: 12px; /* Add padding */
  border-right: 1px solid #ddd;
}

#myTable tr {
  /* Add a bottom border to all table rows */
  border-bottom: 1px solid #ddd;
}

#myTable tr.header, #myTable tr:hover {
  /* Add a grey background color to the table header and on hover */
  background-color: #f1f1f1;
}

</style>


Inputs:
CODE

<input type="text" id="myInput1" onkeyup="myFunctionLN()" placeholder="Search for Last Name ...">
<input type="text" id="myInput2" onkeyup="myFunctionFN()" placeholder="Search for First Name ...">


Functions:
CODE

<script>
function myFunctionLN() {
  // Declare variables
  var input, filter, table, tr, td, i, txtValue;
  input = document.getElementById("myInput1");
  filter = input.value.toUpperCase();
  table = document.getElementById("myTable");
  tr = table.getElementsByTagName("tr");

  // Loop through all table rows, and hide those who don't match the search query
  for (i = 0; i < tr.length; i++) {
    td = tr[i].getElementsByTagName("td")[0];
    if (td) {
      txtValue = td.textContent ||  td.innerText;
      if (txtValue.toUpperCase().indexOf(filter) > -1) {
        tr[i].style.display = "";
      } else {
        tr[i].style.display = "none";
      }
    }
  }
}

function myFunctionFN() {
  // Declare variables
  var input, filter, table, tr, td, i, txtValue;
  input = document.getElementById("myInput2");
  filter = input.value.toUpperCase();
  table = document.getElementById("myTable");
  tr = table.getElementsByTagName("tr");

  // Loop through all table rows, and hide those who don't match the search query
  for (i = 0; i < tr.length; i++) {
    td = tr[i].getElementsByTagName("td")[1];
    if (td) {
      txtValue = td.textContent ||  td.innerText;
      if (txtValue.toUpperCase().indexOf(filter) > -1) {
        tr[i].style.display = "";
      } else {
        tr[i].style.display = "none";
      }
    }
  }
}
</script>
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
Christian J
post May 14 2020, 05:38 PM
Post #2


.
********

Group: WDG Moderators
Posts: 8,462
Joined: 10-August 06
Member No.: 7



QUOTE(EdNerd @ May 14 2020, 08:18 PM) *

Is there an easy way to restrict the second filter function to looking at only the results of the first filter?

Here's a quick idea. I let a single function check both Lastname and Firstname at once:

CODE

<script>
function myFunction()
{
    var input0, input1, filter0, filter1, table, tr, td, i, txtValue0, txtValue1;

    input0 = document.getElementById("myInput0");
    input1 = document.getElementById("myInput1");

    filter0 = input0.value.toUpperCase();
    filter1 = input1.value.toUpperCase();

    table = document.getElementById("myTable");
    tr = table.getElementsByTagName("tr");

    for (i = 0; i < tr.length; i++)
    {
        td0 = tr[i].getElementsByTagName("td")[0];
        td1 = tr[i].getElementsByTagName("td")[1];
        if (td0 && td1)
        {
            txtValue0 = td0.textContent ||  td0.innerText;
            txtValue1 = td1.textContent ||  td1.innerText;

            if (txtValue0.toUpperCase().indexOf(filter0) > -1 && txtValue1.toUpperCase().indexOf(filter1) > -1)
            {
                tr[i].style.display = "";
            }
            else
            {
                tr[i].style.display = "none";
            }
        }
    }
}
</script>


I also renamed the INPUT IDs for consistency:

CODE

<input type="text" id="myInput0" onkeyup="myFunction()" placeholder="Search for Last Name ...">
<input type="text" id="myInput1" onkeyup="myFunction()" placeholder="Search for First Name ...">



QUOTE
Maybe assign a style or such to the first results and use that as a criteria in the second filter??

That might work too, at least if the table is not too large.

This post has been edited by Christian J: May 15 2020, 12:36 PM
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
EdNerd
post May 15 2020, 12:08 PM
Post #3





Group: Members
Posts: 8
Joined: 12-May 20
Member No.: 27,340



Beautiful, Christian!! Absolutely fantastic!
Thank you!! Thank you!! Thank you!! Thank you!!

Can you illuminate on the && operator? Looks like that's a major key to this puzzle.

Ed
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
Christian J
post May 15 2020, 12:35 PM
Post #4


.
********

Group: WDG Moderators
Posts: 8,462
Joined: 10-August 06
Member No.: 7



You're welcome! smile.gif

I'm doing some tests with highlighting as well, but it's actually more tricky since there are so many ways to do it. For example, it could highlight:

- Only when both Lastname and Firstname match.

- When either name matches.

- Initially when either names matches, until you get a match with both names; then only highlight that.

QUOTE(EdNerd @ May 15 2020, 07:08 PM) *

Can you illuminate on the && operator? Looks like that's a major key to this puzzle.

It's an AND logical operator, simply put both expressions on either side must be true in order for the whole IF statement to be true.

There seems to be a lot of more intricate details though, that I'm not qualified to elaborate on.
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
EdNerd
post May 16 2020, 05:40 PM
Post #5





Group: Members
Posts: 8
Joined: 12-May 20
Member No.: 27,340



I was more wondering how it handled a Null or blank string from one of the inputs.

Let's see if I can follow this (comments inline in code):

for (i = 0; i < tr.length; i++)
>> Start at tr=0, and loop until we run out of rows
{
td0 = tr.getElementsByTagName("td")[0];
[i]>> Get the first cell (td) as an object

td1 = tr.getElementsByTagName("td")[1];
[i]>> Get the second td as an object

if (td0 && td1)
>> If you got both a first and a second td
{
txtValue0 = td0.textContent || td0.innerText;
>> Get the value of the text in the first td
txtValue1 = td1.textContent || td1.innerText;
>> Get the value of the text in the second td

if (txtValue0.toUpperCase().indexOf(filter0) > -1 && txtValue1.toUpperCase().indexOf(filter1) > -1)
>> Here's where I'm wondering about the zero-length string in an input. This would seem to say: "As long as you
>> have a filtering match in both td (both conditions are TRUE, display the row. If not, display = "none" - hide the row.
>> But when we enter the first letter in Last Name and the filtering begins, First Name is blank - but I don't have a blank
>> td to match?? How does it match from a blank input? I created another tr that had a blank td[1], and the match
>> still worked. Hence my question of how this handles zero-length / blank / Null values??

{
tr[i].style.display = "";
}
else
{
tr[i].style.display = "none";
}
}
}
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
Christian J
post May 17 2020, 08:08 AM
Post #6


.
********

Group: WDG Moderators
Posts: 8,462
Joined: 10-August 06
Member No.: 7



QUOTE(EdNerd @ May 17 2020, 12:40 AM) *

I was more wondering how it handled a Null or blank string from one of the inputs.

Good question! blink.gif

First, it seem an empty INPUT default value returns an empty string, not null:

CODE
<input type="text" id="foo" value="">

<script type="text/javascript">
alert(typeof document.getElementById('foo').value); // "string"
</script>

This might be the relevant part of the spec:

"the user agent must set the value of the element to the value of the value content attribute, if there is one, or the empty string otherwise"
https://html.spec.whatwg.org/multipage/inpu...ttr-input-value


It also seems indexOf returns "0" when searching for an empty string, not "-1" as one might think:

CODE
<script type="text/javascript">
alert('foo'.indexOf('')); // "0"
</script>


I have no idea why this happens, a web search turned up various discussions that seem to say that's how the spec is defined. See e.g. https://stackoverflow.com/questions/5262418...ing-is-zero-why

BTW, javascript comments must look like this:

CODE
// single line comment

/*  Multiple
line comment */

See also https://developer.mozilla.org/en-US/docs/We...rammar#Comments
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
EdNerd
post May 18 2020, 01:52 PM
Post #7





Group: Members
Posts: 8
Joined: 12-May 20
Member No.: 27,340



Thank you for the answer. (Though admittedly most of it went over my head!)

I knew about marking comments - I just didn't want to make the whole thing a code block. It just made it easier to do the comments.

Thank you so much for all your help in this!!
Ed
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post

Reply to this topicStart new topic
2 User(s) are reading this topic (2 Guests and 0 Anonymous Users)
0 Members:

 



- Lo-Fi Version Time is now: 5th July 2020 - 03:25 PM