I’m building a table that will have several filters. Thus far, I’ve been able to build two filters that work in tandem. The filter values come from dropdown like this (I haven’t included "Org Type" as a filter yet:
Here is my code:
function filterTable_all() {
filter = []
// get filter 1 values and push to array
var input = document.getElementById("KCPWinner");
var values = getSelectValues(input);
filter.push(values.toString().toUpperCase().split(","));
// get filter 2 values and push to array
var input = document.getElementById("yearFounded");
var values = getSelectValues(input);
filter.push(values.toString().toUpperCase().split(","));
// get table
var table = document.getElementById("mytableID");
var tr = table.getElementsByTagName("tr");
// loop through rows for filtering
for (var i = 1; i < tr.length; i++) {
for (var j = 0; j < filter.length; j++) {
// if both filters are selected
if (filter[0] != "" && filter[1] != "") {
if (filter[0].includes(tr[i].children[5].textContent.toUpperCase().trim()) && filter[1].includes(tr[i].children[4].textContent.toUpperCase().trim())){
tr[i].style.display = "block";
}
} // if one filter is selected
else if (filter[0] != "" && filter[1] == "") {
if (filter[0].includes(tr[i].children[5].textContent.toUpperCase().trim())){
tr[i].style.display = "block";
}
} // if the other filter is selected
else if (filter[0] == "" && filter[1] != "") {
if (filter[1].includes(tr[i].children[4].textContent.toUpperCase().trim())) {
tr[i].style.display = "block";
}
}
}
}
}
Basically, I’m grabbing the values selected by the user, and determining if that value should be shown or not. This logic works for two filters.
However, it seems that the way I have done it will not scale well. I will want to add several more filters, but each filter will exponentially increase the if statements. Any ideas on how I can scale this filter logic?
These are the select buttons that are firing the filterTable_all() function (using Django):
<select class="submarket" style="" onchange='filterTable_all()' multiple name="yearFounded" id="yearFounded">
{% for year in filter_options.year_founded %}
{% if year|toStr in liveFilters.year_founded %}
<option class="submarketText checkedClass" value="{{ year }}" selected>{{ year }}</option>
{% else %}
<option class="submarketText" value="{{ year }}">{{ year }}</option>
{% endif %}
{% endfor %}
</select>
Edit: This is all front-end JS filtering
2
Answers
Ok, so @Tarek's response was super helpful, but the foo() function didn't quite work correctly for my use-case. Below is the code I used. It lets multiple filters filter in tandem:
Okay so new answer,
After reviewing I realized your problem wasn’t so simple but I now have an answer
I think your code is not only not scalable due to the issue that you would have exponential if statements, but also optimization. If you had millions of elements you would have to check every element against every filter value for absolutely every call which doesn’t make a lot of sense and would slow things down severely.
Here’s my answer:
Create an object that stores the corresponding index to filter.
This will be easily changeable and can be appended if you add more filters.
Now we can reference this in the function call which will make things more efficient.
Secondly, we need to minimize the amount of loop instances that are occurring which will allow for the inclusion of large amounts of data.
For example: If the year is changed, we only need to check against other filters IF the current element contains a year that is selected. So the preliminary check will be on the filter category that was changed. To do this we can pass in ‘this’ in the onchange event callback which references the current element that was changed.
In javascript we need to loop through every element and check ONLY the index of the filter category that was changed — in this case — years. If it is contained in the current list of selected years, then and only then will it check against other filters. Also, we can minimize code by checking to see if the other filters contain a value that matches the value of the element and corresponding index. If that explanation doesn’t make a lot of sense hopefully it’ll be clearer with my example code: