Client-side Filtering

View as Markdown
The most common way to use filtering in Infinite Table is by configuring filters for columns (this works both for client-side and server-side filtering).
Filtering happens client-side by default - whether the DataSource data property is an array, a Promise or a function. The only exceptions are lazyLoad and livePagination, which filter server-side by default.
When the data property is a function, it's not called again when the filters change. If you also want to reload the data on every filter change, and then filter it client-side, set shouldReloadData.filterValue: true together with filterFunction={defaultFilterFunction}.

Showing the Column Filters#

In order to show the column filter editors in the column headers, you need to specify either the uncontrolled defaultFilterValue property or the controlled filterValue version.
#
Client-side filtering in action
This example shows remote data with local filtering - the data function is called once, and the filtering happens in the browser.
In addition, the filterDelay property is set to 0 for instant feedback.
open
loading demo…
If you still want filtering to be enabled with the default functionality of using the filterValue (or uncontrolled defaultFilterValue), but want to hide the column filter editors, you can set the showColumnFilters property to false.

Using Filter Types#

As already documented in the Understanding Filter Types section, you can specify the types of the filters the <DataSource /> will support, by using the filterTypes property.
The default filter types are string and number - read the next section to see how you can add new operators to those filter types.
A filter type is basically a collection of operators available for a type of data. Each operator needs a name and a function that will be used to filter the data, when that operator is applied.
Using_filter_types_for_filterValue
filterValue={[
  {
    field: 'firstName',
    filter: {
      type: 'string',
      operator: 'includes',
      value: 'John'
    }

  },
  {
    field: 'age',
    filter: {
      type: 'number',
      operator: 'gt',
      value: 30
    }
  }
]}
The above filter value specifies that there are 2 filters applied:
  • the firstName column applies a filter that will only match rows with firstName containining the string John
  • the age column has an additional filter, that will only match rows with age greater than 30
When filtering client-side, the rows are filtered using the functions of the includes operator in the string filter type and of the gt operator in the number filter type.
Here's a snippet of code from the string filter type showing the includes operator:
operators: [
  {
    name: 'includes',
    components: { Icon: IncludesOperatorIcon /* a React Component */ },
    label: 'Includes',
    fn: ({ currentValue, filterValue }) => {
      return (
        typeof currentValue === 'string' &&
        typeof filterValue == 'string' &&
        currentValue.toLowerCase().includes(filterValue.toLowerCase())
      );
    },
  },
  //...
]
Let's now look at another example, of implementing a custom salary filter type.
For this, we override the filterTypes property of the <DataSource /> component:
const filterTypes = {
  salary: {
    defaultOperator: 'gt',
    emptyValues: ['', null, undefined],
    operators: [ /*...*/ ]
  }
};

<DataSource<Developer>
  primaryKey="id"
  data={data}
  filterTypes={filterTypes}
/>
When you specify new filterTypes, the default filter types of string and number are still available - unless the new object contains those keys and overrides them explicitly.
#
Client-side filtering in action with custom filter type
The salary column has a custom filter type, with the following operators: gt, gte, lt and lte.
open
loading demo…

Customizing Default Filter Types#

By default, the string and number filter types are available. You can import the default filter types like this:
import { defaultFilterTypes } from '@infinite-table/infinite-react';
If you want to make all your instances of InfiniteTable have new operators for those filter types, you can simply mutate the exported defaultFilterTypes object.
#
Enhanced string filter type - new 'Not includes' operator
The string columns have a new Not includes operator.
open
loading demo…
When you specify new filterTypes, the default filter types of string and number are still available - unless the new object contains those keys and override them explicitly.

Using a Filter Delay#

In order to save some resources, filtering is batched by default. This is controlled by the filterDelay prop, which, if not specified, defaults to 200 milliseconds. This means, any changes to the column filters, that happen inside a 200ms window (or the current value of filterDelay), will be debounced and only the last value will be used to trigger a filter.
If you want to prevent debouncing/batching filter values, you can set filterDelay to 0.
API calls to setColumnFilter or clearColumnFilter are not batched.

Using a Filter Function Instead of the Column Filters#

With a filterFunction, you decide how the rows are filtered client-side. It is called for every row, and the param it receives also has the current column filters (filterValue and filterTypes), so you can filter in any way you want:
  • call defaultFilterFunction, which Infinite Table exports, to filter by the column filters the same way the built-in filtering does;
  • write your own logic;
  • or combine the two.
import { defaultFilterFunction } from '@infinite-table/infinite-react';

// the built-in column filtering
<DataSource<Developer> primaryKey="id" data={data} filterFunction={defaultFilterFunction} />;

// your own logic only
<DataSource<Developer> primaryKey="id" data={data} filterFunction={(param) => param.data.id > 100} />;

// the column filters, and your own condition
<DataSource<Developer>
  primaryKey="id"
  data={data}
  filterFunction={(param) =>
    defaultFilterFunction(param) && param.data.id > 100
  }
/>;
#
Custom filterFunction example
Loads data from remote location but will only show rows that have id > 100.
open
loading demo…