Adding boolean filtering to Flutter Bloc List Manager

Dana Hartweg
Jul 27, 2020 · 5 min read

Before getting started you’ll definitely want to read about the origination of this package… you can do that here.

All right, now that you’re back, this is the issue we’re going to be tackling today. In the first iteration of the package, only string values were supported as filter conditions. Booleans and numbers require a little extra work to normalize and I didn’t want them to slow down getting the initial version of the package published.

As an extra bonus, I’ll be writing this guide as I work through adding this functionality! You’ll be able to keep track of my thought process the entire time and we’ll be able to pair the work in progress to specific commits in the associated pull request.

Requirements

Overall this should be a rather simple addition, but it’s a good exercise to work through all of your requirements before you start. In this case:

  • By their very nature, boolean values aren’t display-friendly strings. Instead of simply allowing the value of the item into our availableConditions as a raw boolean we need to format it for display.
  • Once we’ve encountered a boolean property there’s no need to revisit that for every source item… the only available options for that property across all items will either be True or False.
  • We’re currently sorting all of the available conditions for a property alphabetically, but one generally expects True to come before False in a list. We’ll want to ensure the default sorting isn’t applied to any field that contains a boolean value.
  • When an active boolean filter condition is encountered, it should properly filter the item list.

What we already know

In looking through the package there are several obvious places requiring modification in order to add boolean support to filter conditions:

Parsing available filter conditions

While one could technically add an active filter condition without it being parsed into availableConditions first, the main use-case will likely be having these boolean properties in the filtering UI.

At the moment we’re explicitly looking for non-empty string values. We’ll still want to check string values this way, but we’ll now want a separate path for parsing boolean values in order to meet our requirements.

Sorting is also applied to every property by default, so we’ll need to amend this path as well.

Tests

Let’s start with some tests!

The first test is the most important as we’ll establish that having multiple items (which will be the most common state of the list) should limit the availableConditions to just True and False without repeating, and in that order. It looks like this:

The second test covers the edge case in which only one item exists in the source list. Essentially we want the same availableConditions any time a boolean property is encountered. The test is nearly identical, it simply reduces the supplied items to 1:

The failing commit can be found here.

Implementation

Let’s start by adjusting our expectation that we only want to operate on non-empty string values. We can start by adding a conditional check for boolean properties and manually adding the values we want to display:

We’re still looping through every item, then every supplied filterProperty on that item… we can save ourselves a little work by only acting on boolean properties once. Funny enough, the above implementation also helps us with our requirement to not sort the provided values for boolean properties.

An alternative approach would have been to check if (value is bool && !booleanProperties.contains(property)), then check again in the loop that is responsible for sorting the filter conditions. I ultimately decided that the one-time hit of removing any boolean property keys from our base set of filter conditions would put us in better shape when dealing with large lists.

The commit for this functionality is here (note: the test run did fail, but the next commit that attempted to diagnose the underlying issue passed… I suspect something was cached improperly).

Adding and removing active conditions

Toggling filter conditions on and off is a core tenant of managing lists in this package. My assumption here is that since we’re treating boolean values as strings once they enter the conditions pipeline, we won’t have to actually modify anything. Let’s see if that holds true!

Tests

We already have a test in place for adding and removing filter conditions, so we can just modify it to also validate that boolean properties and values work as expected.

Here’s the commit for that test.

Implementation

Turns out that no modification is required!

Matching items to filter

The last piece of the puzzle is actually filtering against boolean values. This will be a little trickier since we’re storing the conditions as formatted strings, but the items will still have them as booleans. Shouldn’t be too bad, though.

Tests

We could simply modify the existing tests, but since we’re dealing with a brand new value type I’m going to add one new test and adjust one of the existing tests.

For our new test, we want to ensure that the True value we’ve generated for our conditions (and that would display in our filtering UI) can actually affect the list.

In addition to the new test above, I modified the test directly below as well. I chose that test for two reasons:

  1. It was already testing how multiple active conditions stack to refine the resulting list
  2. By replacing one of the active string conditions with a boolean condition (that would effectively result in the same list) we’re now also testing for items that have the exact same value on a given property… which is something we didn’t actually have covered before

That commit (with tests failing) is right here.

Implementation

We know that items will still have their values stored as booleans, which is good, as that will be our trigger to enter into our boolean filtering path. We also know that we’ve stored the filter condition as a string and capitalized the first character so it’s more display-friendly.

What all of that means is that we’ll have to adjust both sides of the comparison to get an accurate match. The itemValue will need to be converted to a string and the targetValue will need to be lowercased.

Note: the initial temptation would be to just lowercase the targetValue and always compare that to the stringified version of itemValue. That’s actually not a bad idea but comes with some caveats and a few additional questions (especially since we’ve already set up the precedent of case-sensitive filtering).

For now, the above will work just nicely and can be found here.

Wrapping up

Let’s take a look at those requirements one more time to make sure we’ve covered everything:

  • Display-friendly labels — check
  • Avoid redundant property looping — check
  • Separate sorting for boolean values — check
  • Actually filtering the list — check

Just a few documentation updates, and it looks like we’re in good shape!

Hopefully following along with this process in real-time has been a good look at how to take an issue, break it down into requirements, assess what code will need to be modified (and why), and then actually write the tests with the implementation. Even with what turned out to be a relatively simple addition we learned a few new things about the package and identified an area for improvement.

Take care until next time!

https://www.twitter.com/FlutterComm

Flutter Community

Articles and Stories from the Flutter Community

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store