For reference, the full code can be obtained here
I have three select elements which should act as filters on my page, calling the myfilter function. Then, within a table, I use the data- attribute in some <td> elements to "categorise" them without having to set different classes:
<select id="formats" onchange="myfilter('formats', 'mytable')">
<option value="nofilter">--ALL VALUES--</option>
<option value="apple">Apples</option>
<option value="orange">Oranges</option>
<option value="noattr">Unknown</option>
</select>
<table>
<tr>
<td data-format="apple" style="background-color:red;width:10px"> </td>
<td data-model="film" style="background-color:#3ca971;width:10px"> </td>
<td data-type="water" style="background-color:#458985;width:10px"> </td>
<th>1</th>
<td>Michael</td>
<td>New York</td>
<td>M</td>
</tr>
</table>
The myfilter function, adapted from an example from W3Schools, retrieves the value of the selected listbox, determines which column it should look up and compares the custom data- attribute to the value in order to keep the rows visible or hide them:
function myfilter(myelement, reftable) {
var input, filter, table, tr, td, i, j, txtValue, rowstyle, checkvisible;
// Obtains the "value" element of the selected listbox
input = document.getElementById(myelement);
filter = input.value;
table = document.getElementById(reftable);
tr = table.getElementsByTagName("tr");
switch(myelement) {
case "formats":
j = 0;
break;
case "models":
j = 1;
break;
case "types":
j = 2;
}
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[j];
if (td) {
// Retrieves the respective "data-" attribute from <td>
switch(myelement) {
case "formats":
txtValue = td.dataset.format;
break;
case "models":
txtValue = td.dataset.model;
break;
case "types":
txtValue = td.dataset.type;
}
// If there's no style attribute, it's visibleby default
rowstyle = tr[i].getAttribute("style");
if (rowstyle == null) {
checkvisible = true;
}
// If it is hidden, getAttribute returns "display: none;"
else if (rowstyle.includes("none")) {
checkvisible = false;
}
else {
checkvisible = true;
}
// Maintains or hides the row
if (filter == "nofilter") {
tr[i].style.display = "";
}
else if ((txtValue == filter) & checkvisible == true) {
tr[i].style.display = "";
}
else {
tr[i].style.display = "none";
}
}
}
}
The Problem
The way myfilter operates allows for combined filter, but with caveats:
- On a single filter, one has to reset to
--ALL VALUES--before selecting another filter; - When combining filters, the above rule stops me from dynamically switching values while another filter is in place.
How must I change the JavaScript function in order to have the combined filters work as intended (say, like Excel filters, where you keep one filter and changes the other)? I thought about splitting the function in three, but it ends up with the same situation.