Multiple Sorting
By default, if you don't specify otherwise, the DataGrid is configured with single sorting. For multiple sorting, you need to specify the sorting information as an array:
<DataSource<Developer>
primaryKey="id"
data={data}
// we want an array here
defaultSortInfo={[]}
>
<InfiniteTable<Developer> columns={columns} />
</DataSource>
Try clicking the age
column and then the firstName
column.
import { InfiniteTable, DataSource } from '@infinite-table/infinite-react'; import type { InfiniteTablePropColumns } from '@infinite-table/infinite-react'; import * as React from 'react'; type Developer = { id: number; firstName: string; country: string; city: string; currency: string; email: string; preferredLanguage: string; hobby: string; salary: number; age: number; }; const columns: InfiniteTablePropColumns<Developer> = { firstName: { field: 'firstName', header: 'First Name' }, age: { field: 'age', header: 'Age' }, salary: { field: 'salary', header: 'Salary', type: 'number', }, country: { field: 'country', header: 'Country' }, preferredLanguage: { field: 'preferredLanguage' }, id: { field: 'id' }, hobby: { field: 'hobby' }, city: { field: 'city' }, currency: { field: 'currency' }, }; export default function LocalUncontrolledSingleSortingExample() { return ( <> <DataSource<Developer> primaryKey="id" data={dataSource} defaultSortInfo={[]} > <InfiniteTable<Developer> columns={columns} columnDefaultWidth={120} /> </DataSource> </> ); } const dataSource: Developer[] = [ { id: 0, firstName: 'Nya', country: 'India', city: 'Unnao', age: 24, currency: 'JPY', preferredLanguage: 'TypeScript', salary: 60000, hobby: 'sports', email: 'Nya44@gmail.com', }, { id: 1, firstName: 'Axel', country: 'Mexico', city: 'Cuitlahuac', age: 46, currency: 'USD', preferredLanguage: 'TypeScript', salary: 100000, hobby: 'sports', email: 'Axel93@hotmail.com', }, { id: 2, firstName: 'Gonzalo', country: 'United Arab Emirates', city: 'Fujairah', age: 24, currency: 'JPY', preferredLanguage: 'Go', salary: 120000, hobby: 'photography', email: 'Gonzalo_McGlynn34@gmail.com', }, { id: 3, firstName: 'Sherwood', country: 'Mexico', city: 'Tlacolula de Matamoros', age: 24, currency: 'CHF', preferredLanguage: 'Rust', salary: 99000, hobby: 'cooking', email: 'Sherwood_McLaughlin65@hotmail.com', }, { id: 4, firstName: 'Alexandre', country: 'France', city: 'Persan', age: 24, currency: 'EUR', preferredLanguage: 'Go', salary: 97000, hobby: 'reading', email: 'Alexandre_Harber@hotmail.com', }, { id: 5, firstName: 'Mariane', country: 'United States', city: 'Hays', age: 23, currency: 'EUR', preferredLanguage: 'TypeScript', salary: 58000, hobby: 'cooking', email: 'Mariane0@hotmail.com', }, { id: 6, firstName: 'Rosalind', country: 'Mexico', city: 'Nuevo Casas Grandes', age: 23, currency: 'AUD', preferredLanguage: 'JavaScript', salary: 198000, hobby: 'dancing', email: 'Rosalind69@gmail.com', }, { id: 7, firstName: 'Lolita', country: 'Sweden', city: 'Delsbo', age: 22, currency: 'JPY', preferredLanguage: 'TypeScript', salary: 200000, hobby: 'cooking', email: 'Lolita.Hayes@hotmail.com', }, { id: 8, firstName: 'Tre', country: 'Germany', city: 'Bad Camberg', age: 23, currency: 'GBP', preferredLanguage: 'TypeScript', salary: 200000, hobby: 'sports', email: 'Tre28@gmail.com', }, { id
User interaction for multiple sorting
When InfiniteTable
is configured with multiple sorting, this is the behavior you can expect:
Scenario 1
- user clicks a column header to sort by that column - an ascending sort is added, and the column header will contain the sort index -
1
- if user clicks the same column, the sort direction is reversed - sort index is preserved as
1
, but descending order is set. - user clicks the same column again - the column is removed from the sort.
Scenario 2
- user clicks a column header to sort by that column - an ascending sort is added, and the column header will contain the sort index -
1
- user clicks another column - the new column is added to the sort, with ascending order and sort index
2
. The initial clicked column is still the sorted, and that sort is applied first. For equal values on column1
, the sort by column2
is applied. - user clicks column
2
again - the sort direction is reversed for the second column. So now the sort order is1
ascending,2
descending. - user clicks column
2
again - the column is removed from the sort. The sorting now only contains the first column, in ascending order.
Controlled and uncontrolled sorting
As noted above, for multiple sorting, you need to specify an array of objects - see DataSourceSingleSortInfo
for more on the shape of those objects:
// sort by age in descending order, then by `firstName` in ascending order
sortInfo = [
{ field: 'age', type: 'number', dir: -1 },
{ field: 'firstName', dir: 1 },
];
// no sorting
sortInfo = [];
The simplest way to use multiple sorting is via the uncontrolled defaultSortInfo
prop. Specify an empty array as the default value, and multiple sorting will be enabled.
This allows sorting by multiple fields (to which columns are bound) - you can specify however many you want - so when sorting two objects in the DataSource
, the first sortInfo
is used to compare the two, and then, on equal values, the next sortInfo
is used and so on.
Note
If you want to change the sorting from code, after the component is mounted, you need to use the controlled sortInfo
prop.
In this case, make sure you update the sortInfo
prop as a result of user interaction, by using the onSortInfoChange
callback.
This table allows sorting multiple columns - initially the country
column is sorted in descending order and the salary
column is sorted in ascending order. Click the salary
column to toggle the column sort to descending. Clicking it a second time will remove it from the sort altogether.
import { InfiniteTable, DataSource, DataSourceData, } from '@infinite-table/infinite-react'; import type { InfiniteTablePropColumns } from '@infinite-table/infinite-react'; import * as React from 'react'; type Developer = { id: number; firstName: string; lastName: string; country: string; city: string; currency: string; preferredLanguage: string; stack: string; canDesign: 'yes' | 'no'; hobby: string; salary: number; age: number; }; const dataSource: DataSourceData<Developer> = () => { return fetch('https://infinite-table.com/.netlify/functions/json-server' + `/developers100-sql?`) .then((r) => r.json()) .then((data: Developer[]) => data); }; const columns: InfiniteTablePropColumns<Developer> = { firstName: { field: 'firstName' }, country: { field: 'country' }, salary: { field: 'salary', type: 'number', }, age: { field: 'age' }, id: { field: 'id' }, canDesign: { field: 'canDesign' }, preferredLanguage: { field: 'preferredLanguage' }, stack: { field: 'stack' }, hobby: { field: 'hobby' }, city: { field: 'city' }, currency: { field: 'currency' }, }; const domProps = { style: { height: '90vh' } }; export default function LocalUncontrolledMultiSortingExampleWithRemoteData() { return ( <> <DataSource<Developer> primaryKey="id" data={dataSource} defaultSortInfo={[ { field: 'country', dir: -1 }, { field: 'salary', dir: 1 }, ]} sortMode="local" > <InfiniteTable<Developer> domProps={domProps} columns={columns} columnDefaultWidth={120} /> </DataSource> </>
import { InfiniteTable, DataSource, DataSourceData, } from '@infinite-table/infinite-react'; import type { InfiniteTablePropColumns } from '@infinite-table/infinite-react'; import * as React from 'react'; type Developer = { id: number; firstName: string; lastName: string; country: string; city: string; currency: string; preferredLanguage: string; stack: string; canDesign: 'yes' | 'no'; hobby: string; salary: number; age: number; }; const dataSource: DataSourceData<Developer> = ({ sortInfo }) => { if (sortInfo && !Array.isArray(sortInfo)) { sortInfo = [sortInfo]; } const args = [ sortInfo ? 'sortInfo=' + JSON.stringify( sortInfo.map((s) => ({ field: s.field, dir: s.dir, })), ) : null, ] .filter(Boolean) .join('&'); return fetch('https://infinite-table.com/.netlify/functions/json-server' + `/developers100-sql?` + args) .then((r) => r.json()) .then((data: Developer[]) => data); }; const columns: InfiniteTablePropColumns<Developer> = { salary: { field: 'salary', type: 'number', }, age: { field: 'age' }, canDesign: { field: 'canDesign' }, country: { field: 'country' }, preferredLanguage: { field: 'preferredLanguage' }, firstName: { field: 'firstName' }, stack: { field: 'stack' }, id: { field: 'id' }, hobby: { field: 'hobby' }, city: { field: 'city' }, currency: { field: 'currency' }, }; export default function RemoteUncontrolledMultiSortingExample() { return ( <> <DataSource<Developer> primaryKey="id" data={dataSource} defaultSortInfo={[ { field: 'salary', dir: -1, }, ]} sortMode="remote" > <InfiniteTable<Developer> columns={columns} columnDefaultWidth={120} /> </DataSource> </>
Note
If you use uncontrolled sorting via defaultSortInfo
there's no way to switch between single and multiple sorting after the component is mounted. If you have this use-case, you need to use the controlled sortInfo
prop.
Remote Sorting
Sorting remotely makes a lot of sense when using a function as your data
source. Whenever the sort information is changed, the function will be called with all the information needed to retrieve the data from the remote endpoint.
Note
For remote sorting, make sure you specify sortMode="remote"
- if you don't, the data will also be sorted locally in the browser (which most of the times will be harmless, but it means wasted CPU cycles).
import { InfiniteTable, DataSource, DataSourceData, DataSourcePropSortInfo, } from '@infinite-table/infinite-react'; import type { InfiniteTablePropColumns } from '@infinite-table/infinite-react'; import * as React from 'react'; type Developer = { id: number; firstName: string; lastName: string; country: string; city: string; currency: string; preferredLanguage: string; stack: string; canDesign: 'yes' | 'no'; hobby: string; salary: number; age: number; }; const dataSource: DataSourceData<Developer> = ({ sortInfo }) => { if (sortInfo && !Array.isArray(sortInfo)) { sortInfo = [sortInfo]; } const args = [ sortInfo ? 'sortInfo=' + JSON.stringify( sortInfo.map((s) => ({ field: s.field, dir: s.dir, })), ) : null, ] .filter(Boolean) .join('&'); return fetch('https://infinite-table.com/.netlify/functions/json-server' + `/developers100-sql?` + args) .then((r) => r.json()) .then((data: Developer[]) => data); }; const columns: InfiniteTablePropColumns<Developer> = { preferredLanguage: { field: 'preferredLanguage' }, salary: { field: 'salary', type: 'number', }, age: { field: 'age' }, canDesign: { field: 'canDesign' }, country: { field: 'country' }, firstName: { field: 'firstName' }, stack: { field: 'stack' }, id: { field: 'id' }, hobby: { field: 'hobby' }, city: { field: 'city' }, currency: { field: 'currency' }, }; export default function RemoteControlledMultiSortingExample() { const [sortInfo, setSortInfo] = React.useState< DataSourcePropSortInfo<Developer> >([ { field: 'salary', dir: -1, }, ]); return ( <> <DataSource<Developer> primaryKey="id" data={dataSource} sortInfo={sortInfo} sortMode="remote" onSortInfoChange={setSortInfo} > <InfiniteTable<Developer> columns={columns} columnDefaultWidth={220} /> </DataSource> </>
In the example above, remote and controlled sorting are combined - because sortMode="remote"
is specified, the <DataSource />
will call the data
function whenever sorting changes, and will pass in the dataParams
object that contains the sort information.