Building a Dynamic Filter with ES6 JavaScript

Tyler Burdsall
5 min readApr 6, 2018
Image courtesy of devacron.com

As a developer, there will come a time when you need to filter your data based on user-input. Sure, with a few parameters it isn’t very hard to implement the logic needed. But what happens when your user has a LOT of parameters, and those parameters are constantly changing? This is where the beauty of ES6 comes in.

Getting Started: Example Data

For the purposes of this article, we’ll be looking at some made-up housing data. Let’s assume we acquired this data from some API and it returned this JSON data:

Don’t worry about looking through each entry, we’re going to start small for now. Specifically, let’s focus on the fact that each housing entry contains city, state, type, petsAllowed, and saleType. We’ll start with these four parameters to show the basic functionality of our filter.

Storing Filter Parameters

Our next step is to actually contain our filter parameters. Regardless of what framework you’re using (ie. React, Node, etc.), the basic structure will be like this:

Note: each key in the filter matches the key in our JSON data. We use arrays as a way to support multiple selections by the user (ie. a user wants to see listings in both Washington and Oregon).

At some point this filter will be populated. How that is implemented is up to your discretion; all that matters is that the filter is modified properly. Let’s assume for this small example that I want to see listings that match the following criteria:

  • Located in either Oregon or California
  • Is a House
  • Pets are allowed
  • Is available For Sale

Thus, our filter will now look like this to reflect our desired query:

Alright, now that you can see how our filter may look, we need to build our query and filter the data.

Filtering the Data

Did you notice how the city key is empty? We need to ensure we can handle cases like this when a key is empty, otherwise we won’t be correctly filtering our data. We need to make a quick helper function to create a query for us:

All this function will do is take a given filter input and iterate through each of its keys. It ensures that the key is an Array and that it contains at least one element. If so, it adds this to the query and ultimately returns our properly-formatted filter.

Now that we can generate our filter, let’s actually filter our data with another helper function:

This function utilizes the ES6 filter function which provides a very handy way of quickly filtering our data. To summarize what this does:

  1. Goes through each item in data
  2. Compares every key in query to the item’s keys
  3. If the item doesn’t contain the key OR if the value of the item’s key is not in the query, throw out the item. Otherwise, include the item in the filtered results.
  4. Returns the filtered data

Now we can put all of this together to show how this example works.

End Result

Here is the final result for building our basic example (but stay tuned for a more complex example):

If we run this, we will see our filtered data!

$ node basicExample.js[
{
"address": "1234 Example Lane",
"city": "Portland",
"state": "OR",
"zip": "97201",
"listPrice": 350000,
"daysActive": 12,
"type": "House",
"yearBuilt": 1908,
"bedrooms": 3,
"bathrooms": 1,
"squareFootage": 1250,
"hoa": false,
"backyard": true,
"ac": false,
"washerDryerInUnit": true,
"petsAllowed": true,
"saleType": "For Sale"
},
{
"address": "9876 Sunset Dr",
"city": "Los Angeles",
"state": "CA",
"zip": "90025",
"listPrice": 2500000,
"daysActive": 9,
"type": "House",
"yearBuilt": 1965,
"bedrooms": 3,
"bathrooms": 2.5,
"squareFootage": 1125,
"hoa": true,
"backyard": true,
"ac": true,
"washerDryerInUnit": true,
"petsAllowed": true,
"saleType": "For Sale"
}
]
$

Of course, this example doesn’t cover some of the other ways data needs to be filtered. Thankfully, we can modify our code a little to reflect this.

Fine-Tuning the Filter

Now let’s say I want to search for listings with the following parameters:

  • The listing is an Apartment
  • The Apartment is For Rent
  • Is at least $1000 a month, but no more than $1800 a month
  • Has at least 1 bedroom
  • Has a washer and dryer in the unit

We now need to be able to support min and max ranges for some of our keys. Let’s translate these parameters to our filter:

You’ll notice for the listPrice and bedrooms keys we’ve added a min and max key. Also notice how the max value for bedrooms is set to null. We’ll use this to specify that there is no ceiling on how many bedrooms we want to search for.

Let’s update the query builder to handle this change:

All we are doing now is adding another condition to our logic to check if the key is an Object.

But now we need to handle these specific cases. By adding a few if statements in our filterData function we can specify what to do in each case:

Since there are a lot of new changes, I’ll just summarize what was changed:

  • Added an array called keysWithMinMax. This will store all of the keys we are using in the filter that may contain a min or max key (like squareFootage or yearBuilt).
  • Extracted the condition if the item doesn’t contain the key to its own if condition.
  • Added a new logic for testing our keysWithMinMax. Remember how we specified null would be used to indicate that we don’t need to check for these values? That’s how the filter will check whether or not the value needs to be compared. Then it ensures the value is within the specified range.

Now that we’ve updated this, let’s update our script to reflect these changes. I’ll include the old query so you can see the updated results:

Let’s run this to see the results:

$ node advancedExample.js
[
{
"address": "1234 Example Lane",
"city": "Portland",
"state": "OR",
"zip": "97201",
"listPrice": 350000,
"daysActive": 12,
"type": "House",
"yearBuilt": 1908,
"bedrooms": 3,
"bathrooms": 1,
"squareFootage": 1250,
"hoa": false,
"backyard": true,
"ac": false,
"washerDryerInUnit": true,
"petsAllowed": true,
"saleType": "For Sale"
},
{
"address": "9876 Sunset Dr",
"city": "Los Angeles",
"state": "CA",
"zip": "90025",
"listPrice": 2500000,
"daysActive": 9,
"type": "House",
"yearBuilt": 1965,
"bedrooms": 3,
"bathrooms": 2.5,
"squareFootage": 1125,
"hoa": true,
"backyard": true,
"ac": true,
"washerDryerInUnit": true,
"petsAllowed": true,
"saleType": "For Sale"
}
]
----------------------
[
{
"address": "9999 SW 4th Ave",
"city": "Portland",
"state": "OR",
"zip": "97201",
"listPrice": 1200,
"daysActive": 3,
"type": "Apartment",
"yearBuilt": 2002,
"bedrooms": 1,
"bathrooms": 1,
"squareFootage": 655,
"hoa": false,
"backyard": false,
"ac": false,
"washerDryerInUnit": true,
"petsAllowed": true,
"saleType": "For Rent"
},
{
"address": "22 N Washington Dr",
"city": "Seattle",
"state": "WA",
"zip": "98109",
"listPrice": 1750,
"daysActive": 45,
"type": "Apartment",
"yearBuilt": 2010,
"bedrooms": 2,
"bathrooms": 1,
"squareFootage": 950,
"hoa": false,
"backyard": false,
"ac": true,
"washerDryerInUnit": true,
"petsAllowed": true,
"saleType": "For Rent"
}
]
$

Perfect! If you compare the results to the .json file, you’ll see that these results are correct.

Conclusion

With this knowledge you can build a dynamic filter depending on any of the user’s inputs. Plus, you now have a flexible manner of handling the general cases while also specifying detailed parameters. By utilizing JavaScript’s ES6 modules we can also take advantage of the easy-to-use syntax it provides.

--

--

Tyler Burdsall

A software developer in Portland with too many opinions