Filtering is an important feature for large data sets and may vary depending on the structure of the data being filtered. In this post, we'll walk through filtering hierarchical data in the FlexGrid control in an Angular application.

FlexGrid provides support for filtering and allows you to define your own filter function as well. The most common way to do this through the ICollectionView interface, but ICollectionView was designed to handle only flat data, so to handle hierarchical data we'llneed a different approach.

The Problem

Imagine we have a hierarchical collection consisting of “state” objects that have a collection of “city” objects. This could be expressed in JavaScript as follows:

If you assigned this collection to a FlexGrid’s itemsSource property, the grid would automatically display the states, but not the cities.

If you then assigned the value “cities” to the grid’s childItemsPath property, the grid would show the states and then would add child items for each element in the “cities” array. Note that in this case we have only two levels, but this process could continue to any depth.

So far, so good. But the topic of discussion here is filtering this hierarchical data.

By default, the ICollectionView used internally by the FlexGrid only deals with flat data. So you could use it to filter the states only. But what if you wanted to filter by state AND city?

The Solution: Define Rules for the Filter

To do this, we start by defining a few rules for the filter:

The filter will be applied to the “name” property only.

If a state (top level item) satisfies the filter, all its cities will be displayed

If a city (second level item) satisfies the filter, its parent state will be displayed.

Rule #1 is arbitrary. We could use more properties in the filter.

Rule #2 is also arbitrary. If you think showing states without their cities would be useful to users, the rule can be removed.

Rule #3 is the most important one. If a user searched for “Spokane”, the grid should display the city and also its parent state. Failing to do so would create a grid with orphan items.

We'll apply these rules directly to the grid, by traversing all rows and setting their visible property to true only if they pass the filter. The code looks like this:

Since we're building an Angular application, we need to create our Angular Module and Controller.

Create a new file called app.js and copy and paste the code below. Note: the index.html markup already includes a script tag to reference this file. Be sure the file is in the right location on your machine.

On the last line of code, we set the $scope.data object to a CollectionView object, passing the data variable as a parameter. As previously mentioned, the ICollectionView interface represents our data as a flat structure, like an array or list of Objects. If you open the index.html file in a browser, you'll only see the states of each item in the CollectionView.

CollectionView flat structure

In order to display the cities, we need to assign the childItemsPath property of the FlexGrid to "cities." In your index.html file, add the childItemsPath attribute to the wj-flex-grid element and set the attribute to cities like below:

If you save the file and refresh the browser, you'll see the city rows under each state. This is called a Tree View.

Filtering in a TreeView

With the Tree View enabled, it's now time to add the filter! If we use the CollectionView filter, only the parent item’s data properties will be considered when filtering or sorting. Instead we'll create our own filter function. We've already defined our filter function above, but there are a few more steps to finalize our application.

In the index.html file, add an input element and the ng-model directive to allow Angular to detect changes in the input element:

<p><input ng-model="filter" /></p>

In the app.js file, add a $watch function to listen for changes in the filter model.

Finally, add the function that filters! We'll handle filtering by simply hiding the rows that don’t match the filter. So as the user is typing, the grid will automatically update based on our filter function. Copy the updateRowVisibility function from above to the Angular controller.

Now that you've successfully implemented Hierarchical filtering, try using a more complicated data set or modifying the rules/behavior of your filter function.

About the Author

Troy Taylor likes stepping outside of his job role as one of GrapeCity's technical engagement engineers to have an impact in other aspects of the company's business. Troy graduated from the University of Pittsburgh with a Bachelor's of Science in Computer Science before joining the GrapeCity team a year and a half ago. Among many other hobbies, Troy enjoys swimming, travelling, and cooking in his spare time.