Filtering
Filtering allows you to limit the rows available in the table.
Both client-side and server-side filtering are available in Infinite Table - but the way the are configured is pretty similar, so this page documents the common parts, while pointing to the respective pages for the differences.
Configuring Filters for Columns#
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).
You specify an uncontrolled
defaultFilterValue on the <DataSource /> component (or the controlled version, filterValue) and the specified value will be used as the initial filter.Based on the column type, the correct filter editor is displayed in the column header, along with the correct operator icon. In the UI, you can change the operator being used for the filter.
Specifying an initial filter value for the DataSource
<DataSource<Developer>
data={...}
defaultFilterValue={[
{
field: 'age',
filter: {
operator: 'gt',
value: 30,
type: 'number'
}
}
]}
>
<InfiniteTable<Developer>
columns={...}
/>
</DataSource> COPY
If you don't need to specify some initial filters, but want the column filter bar to be visible, you need to specify
defaultFilterValue = [] (or the controlled filterValue = []).Specifying any of those props will make the column filter bar visible.
Whenever filters change,
onFilterChange will be called with the new filter value - note however, it might not be called immediately, due to the filterDelay prop.The above snippet will show a
number filter for the age column. There are two filter types available at this stage in Infinite Table:string- with the following operators available:contains,eq,startsWithandendsWithnumber- with the following operators available:eq,neq,gt,gte,ltandlte
Defining Filterable Columns#
By default, all columns are filterable.
If you want to make columns by default not filterable, use the
columnDefaultFilterable prop and set it to false.You can specifically configure each column by using the
defaultFilterable property - this overrides the global columnDefaultFilterable prop.Defining a Filter Type for a Column#
Besides being filterable, a column can decide what type of filter it will display.
Use the
columns.type property to specify the type of filter the column will use. Using the type property also configures the data type of the column, which in turn determines the sort type.If the type of filter you want to show does not match the column
type, you can specify the filter with the column.filterType property. Only use this when the type of the data differs from the type of the filter (eg: you have a numeric column, with a custom filter type).Understanding Filter Types#
A filter type is a concept that defines how a certain type of data is to be filtered.
A filter type will have
- a
key- the key used to define the filter in thefilterTypesobject - a
label, - an array of values considered to be empty values - when any of these values is used in the filter, the filter will not be applied.
- an array of
operators - a default operator.
Let's imagine you have a
DataSource with developers, each with a salary column, and for that column you want to allow >, >=, < and <= comparisons (operators).For this, you would define the following filter type:
const filterTypes = {
income: {
label: 'Income',
emptyValues: ['', null, undefined],
defaultOperator: 'gt',
operators: [
{
name: 'gt',
label: 'Greater than',
fn: ({ currentValue, filterValue, emptyValues }) => {
if (emptyValues.has(currentValue)) {
return true;
}
return currentValue > filterValue;
},
},
{
name: 'gte',
//...
},
{
name: 'lt',
//...
},
{
name: 'lte',
//...
},
],
},
}; COPY
Each operator for a certain filter type needs to at least have a
name and fn defined. The fn property is a function that will be called when client-side filtering is enabled, with an object that has the following properties:currentValue- the cell value of the current row for the column being filteredfilterValue- the value of the filter editoremptyValues- the array of values considered to be empty values for the filter typedata- the current row data object -typeof DATA_TYPEindex- the index of the current row in the table -numberdataArray- the array of all rows originally in the table -typeof DATA_TYPE[]field?- the field the current column is bound to (can be undefined if the column is not bound to a field)
The
salary column has a custom filter type, with the following operators: gt, gte, lt and lte.View Mode
Fork Forkimport * as React from 'react'; import { DataSourceData, DataSource, InfiniteTable, InfiniteTablePropColumns, } from '@infinite-table/infinite-react'; type Developer = { id: number; firstName: string; lastName: string; currency: string; preferredLanguage: string; stack: string; canDesign: 'yes' | 'no'; salary: number; }; const data: DataSourceData<Developer> = () => { return fetch('https://infinite-table.com/.netlify/functions/json-server' + `/developers1k-sql?`) .then((r) => r.json()) .then((data: Developer[]) => data); }; const columns: InfiniteTablePropColumns<Developer> = { id: { field: 'id', type: 'number', defaultWidth: 100, }, salary: { defaultFilterable: true, field: 'salary', type: 'number', filterType: 'salary', }, firstName: { field: 'firstName', }, stack: { field: 'stack' }, currency: { field: 'currency', defaultFilterable: false }, }; function getIcon(icon: string) { return () => ( <div style={{ width: 20, display: 'flex', justifyContent: 'center', flexFlow: 'row', }} > {icon} </div> ); } const domProps = { style: { height: '100%', }, }; export default () => { return ( <> <React.StrictMode> <DataSource<Developer> data={data} primaryKey="id" defaultFilterValue={[]} filterDelay={0} filterMode="local" filterTypes={{ salary: { defaultOperator: 'gt', emptyValues: ['', null, undefined], operators: [ { name: 'gt', label: 'Greater Than', components: { Icon: getIcon('>'), }, fn: ({ currentValue, filterValue }) => { return currentValue > filterValue; }, }, { name: 'gte', components: { Icon: getIcon('>='), }, label: 'Greater Than or Equal', fn: ({ currentValue, filterValue }) => { return currentValue >= filterValue; }, }, { name: 'lt', components: { Icon: getIcon('<'), }, label: 'Less Than', fn: ({ currentValue, filterValue }) => { return currentValue < filterValue; }, }, { name: 'lte', components: { Icon: getIcon('<='), }, label: 'Less Than or Equal', fn: ({ currentValue, filterValue }) => { return currentValue <= filterValue; }, }, ], }, }} > <InfiniteTable<Developer> domProps={domProps} columnDefaultWidth={150} columnMinWidth={50} columns={columns} /> </DataSource> </React.StrictMode> </>
Specifying the filter mode#
As already mentioned, filtering can happen either client-side or server-side. If the DataSource
data property is a function (and not an array or a Promise), then the filtering will happen server-side by default.However, you can explicitly specify where the filtering should happen by setting the
filterMode property on the <DataSource /> component - possible values arefilterMode="local"- filtering will happen client-sidefilterMode="remote"- filtering will happen remotely and thefilterValuewill be passed as a property to the parameter object sent to thedatafunction.
Filter mode ⚠️
Explicitly specify
filterMode as either "local" or "remote" if you want to change the default behavior.Filtering Columns Not Bound to a Field#
If a column is not bound to a
field, it can still be used for filtering, even client-side filtering, if it is configured with a columns.valueGetter.If you don't need a default filter value, the
filterValue that's set when the user interacts with the column filter will use the column valueGetter to filter values.If however, you need initial filtering by that column, the
filterValue needs to specify a valueGetter itself.defaultFilterValue={[
{
id: 'salary',
valueGetter: ({ data }) => data.salary,
filter: {
operator: 'gt',
value: '',
type: 'number',
}
},
]} COPY
The
salary column is not bound to a field - however, it can still be used for filtering, as it's configured with a valueGetter.View Mode
Fork Forkimport * as React from 'react'; import { DataSourceData, InfiniteTable, InfiniteTablePropColumns, DataSource, } from '@infinite-table/infinite-react'; type Developer = { id: number; firstName: string; lastName: string; currency: string; preferredLanguage: string; stack: string; canDesign: 'yes' | 'no'; salary: number; }; const data: DataSourceData<Developer> = () => { return fetch('https://infinite-table.com/.netlify/functions/json-server' + `/developers1k-sql?`) .then((r) => r.json()) .then((data: Developer[]) => data); }; const columns: InfiniteTablePropColumns<Developer> = { id: { field: 'id', type: 'number', defaultWidth: 70, defaultFilterable: false, }, salary: { // we're intentionally using not binding this column to a `field` type: 'number', header: 'Salary', valueGetter: ({ data }) => data.salary, }, firstName: { field: 'firstName', }, stack: { field: 'stack' }, currency: { field: 'currency' }, }; const domProps = { style: { height: '100%', }, }; export default () => { return ( <> <React.StrictMode> <DataSource<Developer> data={data} primaryKey="id" defaultFilterValue={[ // if you want the salary column to be filtered by default // you need to pass a valueGetter to the filter value // if you don't need a default filter, when you start filtering by // the column, the filter value will use the valueGetter of the column { id: 'salary', valueGetter: ({ data }) => data.salary, filter: { operator: 'gt', value: '', type: 'number', }, }, ]} filterDelay={0} filterMode="local" > <InfiniteTable<Developer> domProps={domProps} columnDefaultWidth={150} columnMinWidth={50} columns={columns} /> </DataSource> </React.StrictMode> </>
Customizing the Filter Icon for Columns#
Columns can customize the filter icon by using the
columns.renderFilterIcon property.The
salary column will show a bolded label when filtered.The
firstName column will show a custom filter icon when filtered.View Mode
Fork Forkimport * as React from 'react'; import { DataSourceData, InfiniteTable, InfiniteTablePropColumns, DataSource, } from '@infinite-table/infinite-react'; type Developer = { id: number; firstName: string; lastName: string; currency: string; preferredLanguage: string; stack: string; canDesign: 'yes' | 'no'; salary: number; }; const data: DataSourceData<Developer> = () => { return fetch('https://infinite-table.com/.netlify/functions/json-server' + `/developers1k-sql?`) .then((r) => r.json()) .then((data: Developer[]) => data); }; const columns: InfiniteTablePropColumns<Developer> = { id: { field: 'id', type: 'number', defaultWidth: 100, }, salary: { field: 'salary', type: 'number', header: ({ filtered }) => { return filtered ? <b>Salary</b> : 'Salary'; }, renderFilterIcon: () => { return null; }, }, firstName: { field: 'firstName', renderFilterIcon: ({ filtered }) => { return filtered ? '🔥' : ''; }, }, stack: { field: 'stack' }, currency: { field: 'currency' }, }; const domProps = { style: { height: '100%', }, }; export default () => { return ( <> <React.StrictMode> <DataSource<Developer> data={data} primaryKey="id" defaultFilterValue={[]} filterDelay={0} filterMode="local" > <InfiniteTable<Developer> domProps={domProps} columnDefaultWidth={150} columnMinWidth={50} columns={columns} /> </DataSource> </React.StrictMode> </>
Client-side filtering
Learn how to use filtering in the browser.
Server-side filtering
Figure out how to use filtering with server-side integration.