Client-side Filtering
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).
If the DataSource
data property is a function (and not an array or a Promise), then the filtering will happen server-side by default.To force client-side filtering, you can explicitly set the
filterMode="local" property on the <DataSource /> component.The possible values for this prop are:
filterMode="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.
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.This example shows remote data with local filtering - it sets
filterMode="local" on the <DataSource /> component.In addition, the
filterDelay property is set to 0 for instant feedback.View Mode
Fork Forkimport * as React from 'react'; import { DataSourceData, InfiniteTable, InfiniteTablePropColumns, DataSource, defaultFilterTypes, } from '@infinite-table/infinite-react'; type Developer = { id: number; firstName: string; lastName: string; currency: string; preferredLanguage: string; stack: string; canDesign: 'yes' | 'no'; salary: number; }; defaultFilterTypes.string.operators.push({ name: 'Not includes', label: 'Not Includes', fn: ({ currentValue, filterValue, emptyValues }) => { if ( emptyValues.includes(currentValue) || emptyValues.includes(filterValue) ) { return true; } return ( typeof currentValue === 'string' && typeof filterValue == 'string' && !currentValue.toLowerCase().includes(filterValue.toLowerCase()) ); }, }); 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: { field: 'salary', type: 'number', }, 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={[]} filterDelay={0} filterMode="local" > <InfiniteTable<Developer> domProps={domProps} columnDefaultWidth={150} columnMinWidth={50} columns={columns} /> </DataSource> </React.StrictMode> </>
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 } } ]}
COPY
The above filter value specifies that there are 2 filters applied:
- the
firstNamecolumn applies a filter that will only match rows withfirstNamecontainining the stringJohn - the
agecolumn has an additional filter, that will only match rows withagegreater than30
If
filterMode is set to local, then the filtering will happen client-side, using the filtering functions specified by includes operator in the string filter type and 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: /* a React Component */ },
label: 'Includes',
fn: ({ currentValue, filterValue }) => {
return (
typeof currentValue === 'string' &&
typeof filterValue == 'string' &&
currentValue.toLowerCase().includes(filterValue.toLowerCase())
);
},
},
//...
] COPY
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>
filterTypes={filterTypes}
COPY
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.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> </>
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'; COPY
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.The
string columns have a new Not includes operator.View Mode
Fork Forkimport * as React from 'react'; import { DataSourceData, InfiniteTable, InfiniteTablePropColumns, DataSource, defaultFilterTypes, } from '@infinite-table/infinite-react'; type Developer = { id: number; firstName: string; lastName: string; currency: string; preferredLanguage: string; stack: string; canDesign: 'yes' | 'no'; salary: number; }; defaultFilterTypes.string.operators.push({ name: 'Not contains', label: 'Not Contains', fn: ({ currentValue, filterValue, emptyValues }) => { if ( emptyValues.includes(currentValue) || emptyValues.includes(filterValue) ) { return true; } return ( typeof currentValue === 'string' && typeof filterValue == 'string' && !currentValue.toLowerCase().includes(filterValue.toLowerCase()) ); }, }); 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, }, firstName: { field: 'firstName', }, stack: { field: 'stack' }, salary: { field: 'salary', type: 'number', }, currency: { field: 'currency', defaultFilterable: false }, }; 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> </>
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#
For client-side rendering, it's possible that instead of showing a column filter bar, you use a custom
filterFunction to filter the data.In this case, the filtering will happen client-side ... of course 🤦♂️.
Loads data from remote location but will only show rows that have
id > 100.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 }, }; const domProps = { style: { height: '100%', }, }; export default () => { return ( <> <React.StrictMode> <DataSource<Developer> data={data} primaryKey="id" filterFunction={({ data }) => { return data.id > 100; }} > <InfiniteTable<Developer> domProps={domProps} columnDefaultWidth={150} columnMinWidth={50} columns={columns} /> </DataSource> </React.StrictMode> </>