ColumnsColumn Filter

Column Filtering

Column filtering can be set / configured in 2 locations:

  1. DataSource (API)
  2. Grid instance (API)

In addition, you can configure a column specific filtering behaviour in the column definitions.

This page refer to client-side filtering where filtering is done in the browser and not on the server. For more information read the datasource quick-through.

Activating a filter

Activating is done through on of the APIs (DataSource or Grid).

There are 2 filter types:

  • Value filter
  • Predicate filter

Value filter is managed by the grid, we are activating the filter by providing a value that we want to find a match to in one or more columns. If the value has a match the row will pass the filter, otherwise it will get filtered out.

Predicate Filter is un-managed, we have full control over the filtering process. We provide a predicate function that accepts a row and a collection of columns and return true if the row passed the filter and false if not.

In the most basic level all filters are predicates , the value filter is just an API to organize and simplify the use of function predicates.

Value Filter

The value filter approach is simple and consistent across grid's. It relays on pre-defined filtering behaviour which is used to filter the value.

The grid comes with one pre-defined behaviour that compares the inclusion (text) of the provided value in a column value. For example, if the filter value is "oh" and the value in the column name for a given row is "John", it will pass the filter.

Here we search for oh in either column name or email:

grid.setFilter('oh', ['name', 'email']);
In the example above me make use of the Grid instance (API) , which allows us to provide a string reference to a column

Of course, this is too generic, filtering the value 11 will return 211, 11, 341123, etc...

Value filter behaviour

To really leverage the value filter we need to control how certain column filter certain values.

This is done in the column definition, where we can set the filter property which will act as a predicate specifically for the column it is defined on.

export interface PblColumnDefinition extends PblBaseColumnDefinition {
  // ...

  /**
   * A custom predicate function to filter rows using the current column.
   *
   * Valid only when filtering by value.
   * See `PblDataSource.setFilter` for more information.
   */
  filter?: DataSourceColumnPredicate;
  // ...
}

The definition for DataSourceColumnPredicate:

/**
 * A function the return true then the value should be included in the result or false when not.
 * This is a single column filter predicated, returning false will filter out the entire row but the
 * predicate is only intended to filter a specific column.
 */
export type DataSourceColumnPredicate = (filterValue: any, colValue: any, row?: any, col?: PblColumn) => boolean;

A function that accept a filterValue (the value to filter by), a colValue (the value of the cell for the column for a given row), the row and the column instance.

For example, a numeric filter:

const numericFilter = (filterValue: number, colValue: number) => filterValue === colValue

Now, let's build a numeric range filter:

const numericFilter = (filterValue: number, colValue: number) => colValue > ???  && colValue < ???

We're stuck, we need the min / max value of the range. The filterValue does not have to be of the same type of the column we're filtering...

const numericRangeFilter = (filterValue: { min: number, max: number }, colValue: number) => colValue > filterValue.min && colValue < filterValue.max

Which we will activate like this:

grid.setFilter({ min: 21, max: 120 }, ['age']);

These are simple examples, they can be extended per your requirements, using a dedicated library or your own custom logic.

Real-world value filters

As you might have realized by now, value filters are powerful because they allow to create a reusable filtering system for the entire app without much effort.

Combined with the type property you can automate the assignment of filters based on types.

In the future, we hope to release a column pack package with pre-defined sorting and filtering predicates attached to pre-defined types.

Value filter cons

Currently, you can't join 2 (or more) values filters into a single AND or OR expression

Predicate Filter

The predicate filter is the "hands-on" manual approach.

Instead of accepting a value, it accepts a function of type DataSourcePredicate:

/**
 * A function the return true then the row should be included in the result or false when not.
 * @param row The row in the data source that the filter apply on
 * @param properties A list of column instances (`PblColumn`) to filter values by.
 */
export type DataSourcePredicate = (row: any, properties: PblColumn[]) => boolean;

Like the value filter predicate function (DataSourceColumnPredicate) its job is to determine if a row is passed the filter or not (filtered out).

However, value filter predicates work on the column level, a specific column in a row.

Here we work on the row level, the grid will provide the rows to the filter, one by one, including the columns participating the in filtering process. The filter is responsible from here, for the entire row including it's columns.

In most cases, value filters will do the job, but for more complex scenarios we can use the predicate filter.

A good example for predicate filtering in action is the multi-column filter which demonstrate filtering using 2 (or more) columns at the same time.

Value filters are implemented using a special predicate filter that manage the process.

Syncing the filter

Syncing the filter is simply re-running the filtering process with the current filter registered.

Calling setFilter with the same filter function will not work because the filter is cached.

grid.setFilter({myPredicateFunction, ['age']);

Instead, use:

grid.ds.syncFilter();

You might ask why a re-running the filter is needed? great question!

If you're running a value filter then no, you don't need to sync the filter, just call setFilter with the new value.

If you're running a predicate filter, use the syncFilter to re-run the filter when the value changes. In predicate filter there is no "value" to filter by, you provide it so a mechanism to update the filter based on value updates is required.

The the multi-column filter example (link above) makes use of syncFilter.

Clearing The filter

To clear the current filter call the setFilter method with no parameters

grid.setFilter();

Accessing Filtered Data

The data store holds the last filtered subset, located in PblDataSource.filteredData.

The filteredData property will always return an array, either empty or populated.

Shlomi Assaf © 2020. Code licensed under an MIT-style License. Documentation licensed under CC BY 4.0.

Version 3.1.4 using angular 11.2.7 and cdk 11.2.6 (hash: ad60966)