diff --git a/docs/pages/api-docs/data-grid/data-grid.md b/docs/pages/api-docs/data-grid/data-grid.md
index 3f88ce8593952..f868176c016ee 100644
--- a/docs/pages/api-docs/data-grid/data-grid.md
+++ b/docs/pages/api-docs/data-grid/data-grid.md
@@ -83,7 +83,7 @@ import { DataGrid } from '@material-ui/data-grid';
| onRowEnter | (param: GridRowParams, event: React.MouseEvent) => void | | Callback fired when a mouse enter comes from a row container element. |
| onRowLeave | (param: GridRowParams, event: React.MouseEvent) => void | | Callback fired when a mouse leave event comes from a row container element. |
| onSelectionModelChange | (param: GridSelectionModelChangeParams) => void | | Callback fired when the selection state of one or multiple rows changes. |
-| onSortModelChange | (param: GridSortModelParams) => void | | Callback fired when the sort model changes before a column is sorted. |
+| onSortModelChange | (model: GridSortModel) => void | | Callback fired when the sort model changes before a column is sorted. |
| page | number | 1 | Set the current page. |
| pageSize | number | 100 | Set the number of rows in one page. |
| paginationMode | GridFeatureMode | 'client' | Pagination can be processed on the server or client-side. Set it to 'client' if you would like to handle the pagination on the client-side. Set it to 'server' if you would like to handle the pagination on the server-side. |
diff --git a/docs/pages/api-docs/data-grid/x-grid.md b/docs/pages/api-docs/data-grid/x-grid.md
index eac509a0288d2..ff550b3d51709 100644
--- a/docs/pages/api-docs/data-grid/x-grid.md
+++ b/docs/pages/api-docs/data-grid/x-grid.md
@@ -89,7 +89,7 @@ import { XGrid } from '@material-ui/x-grid';
| onRowLeave | (param: GridRowParams, event: React.MouseEvent) => void | | Callback fired when a mouse leave event comes from a row container element. |
| onRowsScrollEnd | (param: GridRowScrollEndParams) => void | | Callback fired when scrolling to the bottom of the grid viewport. |
| onSelectionModelChange | (param: GridSelectionModelChangeParams) => void | | Callback fired when the selection state of one or multiple rows changes. |
-| onSortModelChange | (param: GridSortModelParams) => void | | Callback fired when the sort model changes before a column is sorted. |
+| onSortModelChange | (model: GridSortModel) => void | | Callback fired when the sort model changes before a column is sorted. |
| page | number | 1 | Set the current page. |
| pageSize | number | 100 | Set the number of rows in one page. |
| pagination | boolean | false | If `true`, pagination is enabled. |
diff --git a/docs/src/pages/components/data-grid/sorting/BasicSortingGrid.js b/docs/src/pages/components/data-grid/sorting/BasicSortingGrid.js
index ff7936aa170f5..082d5be6863d6 100644
--- a/docs/src/pages/components/data-grid/sorting/BasicSortingGrid.js
+++ b/docs/src/pages/components/data-grid/sorting/BasicSortingGrid.js
@@ -9,16 +9,19 @@ export default function BasicSortingGrid() {
maxColumns: 6,
});
+ const [sortModel, setSortModel] = React.useState([
+ {
+ field: 'commodity',
+ sort: 'asc',
+ },
+ ]);
+
return (
setSortModel(model)}
/>
);
diff --git a/docs/src/pages/components/data-grid/sorting/BasicSortingGrid.tsx b/docs/src/pages/components/data-grid/sorting/BasicSortingGrid.tsx
index 66c899ceb32ac..b337d3abbf86f 100644
--- a/docs/src/pages/components/data-grid/sorting/BasicSortingGrid.tsx
+++ b/docs/src/pages/components/data-grid/sorting/BasicSortingGrid.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { DataGrid, GridSortDirection } from '@material-ui/data-grid';
+import { DataGrid, GridSortModel } from '@material-ui/data-grid';
import { useDemoData } from '@material-ui/x-grid-data-generator';
export default function BasicSortingGrid() {
@@ -9,16 +9,19 @@ export default function BasicSortingGrid() {
maxColumns: 6,
});
+ const [sortModel, setSortModel] = React.useState([
+ {
+ field: 'commodity',
+ sort: 'asc',
+ },
+ ]);
+
return (
setSortModel(model)}
/>
);
diff --git a/docs/src/pages/components/data-grid/sorting/ComparatorSortingGrid.js b/docs/src/pages/components/data-grid/sorting/ComparatorSortingGrid.js
index eb36240339cc0..7c475ede25c13 100644
--- a/docs/src/pages/components/data-grid/sorting/ComparatorSortingGrid.js
+++ b/docs/src/pages/components/data-grid/sorting/ComparatorSortingGrid.js
@@ -68,17 +68,22 @@ const rows = [
},
];
-const sortModel = [
- {
- field: 'username',
- sort: 'asc',
- },
-];
-
export default function ComparatorSortingGrid() {
+ const [sortModel, setSortModel] = React.useState([
+ {
+ field: 'username',
+ sort: 'asc',
+ },
+ ]);
+
return (
-
+ setSortModel(model)}
+ />
);
}
diff --git a/docs/src/pages/components/data-grid/sorting/ComparatorSortingGrid.tsx b/docs/src/pages/components/data-grid/sorting/ComparatorSortingGrid.tsx
index ae0ad2891ad25..2d73d2439a5f2 100644
--- a/docs/src/pages/components/data-grid/sorting/ComparatorSortingGrid.tsx
+++ b/docs/src/pages/components/data-grid/sorting/ComparatorSortingGrid.tsx
@@ -5,6 +5,7 @@ import {
DataGrid,
GridSortDirection,
GridValueGetterParams,
+ GridSortModel,
} from '@material-ui/data-grid';
import {
randomCreatedDate,
@@ -74,17 +75,21 @@ const rows: GridRowsProp = [
},
];
-const sortModel = [
- {
- field: 'username',
- sort: 'asc' as GridSortDirection,
- },
-];
-
export default function ComparatorSortingGrid() {
+ const [sortModel, setSortModel] = React.useState([
+ {
+ field: 'username',
+ sort: 'asc' as GridSortDirection,
+ },
+ ]);
return (
-
+ setSortModel(model)}
+ />
);
}
diff --git a/docs/src/pages/components/data-grid/sorting/MultiSortingGrid.js b/docs/src/pages/components/data-grid/sorting/MultiSortingGrid.js
index 281871a597d52..ac98378ce0ee4 100644
--- a/docs/src/pages/components/data-grid/sorting/MultiSortingGrid.js
+++ b/docs/src/pages/components/data-grid/sorting/MultiSortingGrid.js
@@ -9,20 +9,23 @@ export default function MultiSortingGrid() {
maxColumns: 6,
});
+ const [sortModel, setSortModel] = React.useState([
+ {
+ field: 'commodity',
+ sort: 'asc',
+ },
+ {
+ field: 'desk',
+ sort: 'desc',
+ },
+ ]);
+
return (
setSortModel(model)}
/>
);
diff --git a/docs/src/pages/components/data-grid/sorting/MultiSortingGrid.tsx b/docs/src/pages/components/data-grid/sorting/MultiSortingGrid.tsx
index 590d40040fc72..0dba4863a79e3 100644
--- a/docs/src/pages/components/data-grid/sorting/MultiSortingGrid.tsx
+++ b/docs/src/pages/components/data-grid/sorting/MultiSortingGrid.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { XGrid, GridSortDirection } from '@material-ui/x-grid';
+import { XGrid, GridSortDirection, GridSortModel } from '@material-ui/x-grid';
import { useDemoData } from '@material-ui/x-grid-data-generator';
export default function MultiSortingGrid() {
@@ -9,20 +9,23 @@ export default function MultiSortingGrid() {
maxColumns: 6,
});
+ const [sortModel, setSortModel] = React.useState([
+ {
+ field: 'commodity',
+ sort: 'asc' as GridSortDirection,
+ },
+ {
+ field: 'desk',
+ sort: 'desc' as GridSortDirection,
+ },
+ ]);
+
return (
setSortModel(model)}
/>
);
diff --git a/docs/src/pages/components/data-grid/sorting/OrderSortingGrid.js b/docs/src/pages/components/data-grid/sorting/OrderSortingGrid.js
index c826bb81f14f3..14a2bbe4520d3 100644
--- a/docs/src/pages/components/data-grid/sorting/OrderSortingGrid.js
+++ b/docs/src/pages/components/data-grid/sorting/OrderSortingGrid.js
@@ -9,16 +9,19 @@ export default function OrderSortingGrid() {
maxColumns: 6,
});
+ const [sortModel, setSortModel] = React.useState([
+ {
+ field: 'commodity',
+ sort: 'asc',
+ },
+ ]);
+
return (
setSortModel(model)}
{...data}
/>
diff --git a/docs/src/pages/components/data-grid/sorting/OrderSortingGrid.tsx b/docs/src/pages/components/data-grid/sorting/OrderSortingGrid.tsx
index f1787f08c20d1..ae7f9cae87fe6 100644
--- a/docs/src/pages/components/data-grid/sorting/OrderSortingGrid.tsx
+++ b/docs/src/pages/components/data-grid/sorting/OrderSortingGrid.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { DataGrid, GridSortDirection } from '@material-ui/data-grid';
+import { DataGrid, GridSortDirection, GridSortModel } from '@material-ui/data-grid';
import { useDemoData } from '@material-ui/x-grid-data-generator';
export default function OrderSortingGrid() {
@@ -9,16 +9,19 @@ export default function OrderSortingGrid() {
maxColumns: 6,
});
+ const [sortModel, setSortModel] = React.useState([
+ {
+ field: 'commodity',
+ sort: 'asc' as GridSortDirection,
+ },
+ ]);
+
return (
setSortModel(model)}
{...data}
/>
diff --git a/docs/src/pages/components/data-grid/sorting/ServerSortingGrid.js b/docs/src/pages/components/data-grid/sorting/ServerSortingGrid.js
index caf9017e063b2..293e4c21fb312 100644
--- a/docs/src/pages/components/data-grid/sorting/ServerSortingGrid.js
+++ b/docs/src/pages/components/data-grid/sorting/ServerSortingGrid.js
@@ -39,10 +39,8 @@ export default function ServerSortingGrid() {
const [rows, setRows] = React.useState([]);
const [loading, setLoading] = React.useState(false);
- const handleSortModelChange = (params) => {
- if (params.sortModel !== sortModel) {
- setSortModel(params.sortModel);
- }
+ const handleSortModelChange = (newModel) => {
+ setSortModel(newModel);
};
React.useEffect(() => {
diff --git a/docs/src/pages/components/data-grid/sorting/ServerSortingGrid.tsx b/docs/src/pages/components/data-grid/sorting/ServerSortingGrid.tsx
index cef096f850ac1..3a2eea237e057 100644
--- a/docs/src/pages/components/data-grid/sorting/ServerSortingGrid.tsx
+++ b/docs/src/pages/components/data-grid/sorting/ServerSortingGrid.tsx
@@ -1,10 +1,5 @@
import * as React from 'react';
-import {
- GridRowsProp,
- DataGrid,
- GridSortModel,
- GridSortModelParams,
-} from '@material-ui/data-grid';
+import { GridRowsProp, DataGrid, GridSortModel } from '@material-ui/data-grid';
import { useDemoData, GridData } from '@material-ui/x-grid-data-generator';
function loadServerRows(sortModel: GridSortModel, data: GridData): Promise {
@@ -42,10 +37,8 @@ export default function ServerSortingGrid() {
const [rows, setRows] = React.useState([]);
const [loading, setLoading] = React.useState(false);
- const handleSortModelChange = (params: GridSortModelParams) => {
- if (params.sortModel !== sortModel) {
- setSortModel(params.sortModel);
- }
+ const handleSortModelChange = (newModel: GridSortModel) => {
+ setSortModel(newModel);
};
React.useEffect(() => {
diff --git a/packages/grid/_modules_/grid/hooks/features/sorting/useGridSorting.ts b/packages/grid/_modules_/grid/hooks/features/sorting/useGridSorting.ts
index a5559c984d6cf..c06c24be57f56 100644
--- a/packages/grid/_modules_/grid/hooks/features/sorting/useGridSorting.ts
+++ b/packages/grid/_modules_/grid/hooks/features/sorting/useGridSorting.ts
@@ -8,13 +8,13 @@ import {
GRID_ROWS_UPDATE,
GRID_SORT_MODEL_CHANGE,
} from '../../../constants/eventsConstants';
+import { GridComponentProps } from '../../../GridComponentProps';
import { GridApiRef } from '../../../models/api/gridApiRef';
import { GridSortApi } from '../../../models/api/gridSortApi';
import { GridCellValue } from '../../../models/gridCell';
import { GridColDef } from '../../../models/colDef/gridColDef';
import { GridFeatureModeConstant } from '../../../models/gridFeatureMode';
import { GridColumnHeaderParams } from '../../../models/params/gridColumnHeaderParams';
-import { GridSortModelParams } from '../../../models/params/gridSortModelParams';
import { GridRowId, GridRowModel } from '../../../models/gridRows';
import {
GridFieldComparatorList,
@@ -26,7 +26,7 @@ import {
import { isDesc, nextGridSortDirection } from '../../../utils/sortingUtils';
import { isEnterKey } from '../../../utils/keyboardUtils';
import { isDeepEqual } from '../../../utils/utils';
-import { useGridApiEventHandler, useGridApiOptionHandler } from '../../root/useGridApiEventHandler';
+import { useGridApiEventHandler } from '../../root/useGridApiEventHandler';
import { useGridApiMethod } from '../../root/useGridApiMethod';
import { optionsSelector } from '../../utils/optionsSelector';
import { useLogger } from '../../utils/useLogger';
@@ -35,11 +35,10 @@ import { useGridSelector } from '../core/useGridSelector';
import { useGridState } from '../core/useGridState';
import { gridRowCountSelector } from '../rows/gridRowsSelector';
import { sortedGridRowIdsSelector, sortedGridRowsSelector } from './gridSortingSelector';
-import { GridComponentProps } from '../../../GridComponentProps';
export const useGridSorting = (
apiRef: GridApiRef,
- props: Pick,
+ props: Pick,
) => {
const logger = useLogger('useGridSorting');
@@ -48,15 +47,6 @@ export const useGridSorting = (
const visibleColumns = useGridSelector(apiRef, visibleGridColumnsSelector);
const rowCount = useGridSelector(apiRef, gridRowCountSelector);
- const getSortModelParams = React.useCallback(
- (sortModel: GridSortModel): GridSortModelParams => ({
- sortModel,
- api: apiRef.current,
- columns: apiRef.current.getAllColumns(),
- }),
- [apiRef],
- );
-
const upsertSortModel = React.useCallback(
(field: string, sortItem?: GridSortItem): GridSortModel => {
const existingIdx = gridState.sorting.sortModel.findIndex((c) => c.field === field);
@@ -215,10 +205,9 @@ export const useGridSorting = (
if (visibleColumns.length === 0) {
return;
}
- apiRef.current.publishEvent(GRID_SORT_MODEL_CHANGE, getSortModelParams(sortModel));
apiRef.current.applySorting();
},
- [setGridState, forceUpdate, visibleColumns.length, apiRef, getSortModelParams],
+ [setGridState, forceUpdate, visibleColumns.length, apiRef],
);
const sortColumn = React.useCallback(
@@ -304,8 +293,6 @@ export const useGridSorting = (
useGridApiEventHandler(apiRef, GRID_ROWS_UPDATE, apiRef.current.applySorting);
useGridApiEventHandler(apiRef, GRID_COLUMNS_CHANGE, onColUpdated);
- useGridApiOptionHandler(apiRef, GRID_SORT_MODEL_CHANGE, props.onSortModelChange);
-
const sortApi: GridSortApi = {
getSortModel,
getSortedRows,
@@ -329,11 +316,24 @@ export const useGridSorting = (
}, [rowCount, apiRef, logger]);
React.useEffect(() => {
- const sortModel = options.sortModel || [];
+ apiRef.current.updateControlState({
+ stateId: 'sortModel',
+ propModel: props.sortModel,
+ propOnChange: props.onSortModelChange,
+ stateSelector: (state) => state.sorting.sortModel,
+ onChangeCallback: (model) => {
+ apiRef.current.publishEvent(GRID_SORT_MODEL_CHANGE, model);
+ },
+ });
+ }, [apiRef, props.sortModel, props.onSortModelChange]);
+
+ React.useEffect(() => {
+ const sortModel = props.sortModel || [];
const oldSortModel = apiRef.current.state.sorting.sortModel;
if (!isDeepEqual(sortModel, oldSortModel)) {
+ setGridState((state) => ({ ...state, sorting: { ...state.sorting, sortModel } }));
// we use apiRef to avoid watching setSortModel as it will trigger an update on every state change
- apiRef.current.setSortModel(sortModel);
+ apiRef.current.applySorting();
}
- }, [options.sortModel, apiRef]);
+ }, [props.sortModel, apiRef, setGridState]);
};
diff --git a/packages/grid/_modules_/grid/models/gridOptions.tsx b/packages/grid/_modules_/grid/models/gridOptions.tsx
index 0a20cc805febe..e9eb1e33f8600 100644
--- a/packages/grid/_modules_/grid/models/gridOptions.tsx
+++ b/packages/grid/_modules_/grid/models/gridOptions.tsx
@@ -13,7 +13,6 @@ import { GridCellParams } from './params/gridCellParams';
import { GridColumnHeaderParams } from './params/gridColumnHeaderParams';
import { GridPageChangeParams } from './params/gridPageChangeParams';
import { GridRowParams } from './params/gridRowParams';
-import { GridSortModelParams } from './params/gridSortModelParams';
import { GridSelectionModel } from './gridSelectionModel';
import { GridSortDirection, GridSortModel } from './gridSortModel';
import {
@@ -417,9 +416,9 @@ export interface GridOptions {
onSelectionModelChange?: (selectionModel: GridRowId[]) => void;
/**
* Callback fired when the sort model changes before a column is sorted.
- * @param param With all properties from [[GridSortModelParams]].
+ * @param param With all properties from [[GridSortModel]].
*/
- onSortModelChange?: (params: GridSortModelParams) => void;
+ onSortModelChange?: (model: GridSortModel) => void;
/**
* Callback fired when the state of the grid is updated.
*/
diff --git a/packages/grid/x-grid-data-generator/src/useDemoData.ts b/packages/grid/x-grid-data-generator/src/useDemoData.ts
index db5b8e0012007..3889a1b56f659 100644
--- a/packages/grid/x-grid-data-generator/src/useDemoData.ts
+++ b/packages/grid/x-grid-data-generator/src/useDemoData.ts
@@ -80,11 +80,24 @@ function deepFreeze(object) {
}
export const useDemoData = (options: DemoDataOptions): DemoDataReturnType => {
- const [data, setData] = React.useState({ columns: [], rows: [] });
const [rowLength, setRowLength] = React.useState(options.rowLength);
const [index, setIndex] = React.useState(0);
const [loading, setLoading] = React.useState(true);
+ const getColumns = React.useCallback(() => {
+ let columns =
+ options.dataSet === 'Commodity'
+ ? getCommodityColumns(options.editable)
+ : getEmployeeColumns();
+
+ if (options.maxColumns) {
+ columns = columns.slice(0, options.maxColumns);
+ }
+ return columns;
+ }, [options.dataSet, options.editable, options.maxColumns]);
+
+ const [data, setData] = React.useState({ columns: getColumns(), rows: [] });
+
React.useEffect(() => {
const cacheKey = `${options.dataSet}-${rowLength}-${index}-${options.maxColumns}`;
@@ -101,17 +114,9 @@ export const useDemoData = (options: DemoDataOptions): DemoDataReturnType => {
(async () => {
setLoading(true);
- let columns =
- options.dataSet === 'Commodity'
- ? getCommodityColumns(options.editable)
- : getEmployeeColumns();
-
- if (options.maxColumns) {
- columns = columns.slice(0, options.maxColumns);
- }
let newData;
-
+ const columns = getColumns();
if (rowLength > 1000) {
newData = await getRealData(1000, columns);
newData = await extrapolateSeed(rowLength, columns, newData);
@@ -136,7 +141,7 @@ export const useDemoData = (options: DemoDataOptions): DemoDataReturnType => {
return () => {
active = false;
};
- }, [rowLength, options.dataSet, index, options.maxColumns, options.editable]);
+ }, [rowLength, data.columns, options.dataSet, options.maxColumns, index, getColumns]);
return {
data,
diff --git a/packages/grid/x-grid/src/tests/sorting.XGrid.test.tsx b/packages/grid/x-grid/src/tests/sorting.XGrid.test.tsx
index 1a6b12ef39296..3ea87712d4eda 100644
--- a/packages/grid/x-grid/src/tests/sorting.XGrid.test.tsx
+++ b/packages/grid/x-grid/src/tests/sorting.XGrid.test.tsx
@@ -1,8 +1,13 @@
import * as React from 'react';
-import { GridApiRef, GridSortModel, useGridApiRef } from '@material-ui/data-grid';
+import {
+ GridApiRef,
+ GridComponentProps,
+ GridSortModel,
+ useGridApiRef,
+} from '@material-ui/data-grid';
import { XGrid } from '@material-ui/x-grid';
import { expect } from 'chai';
-import { useFakeTimers } from 'sinon';
+import { spy, useFakeTimers } from 'sinon';
import { getColumnValues, getCell, getColumnHeaderCell } from 'test/utils/helperFn';
import {
createClientRenderStrictMode,
@@ -54,21 +59,16 @@ describe(' - Sorting', () => {
let apiRef: GridApiRef;
- const TestCase = (props: {
- rows?: any[];
- sortModel: GridSortModel;
- disableMultipleColumnsSorting?: boolean;
- }) => {
- const { sortModel, rows, disableMultipleColumnsSorting } = props;
+ const TestCase = (props: Partial) => {
+ const { rows, ...other } = props;
apiRef = useGridApiRef();
return (
);
@@ -115,7 +115,8 @@ describe(' - Sorting', () => {
});
it('should allow apiRef to setSortModel', () => {
- renderBrandSortedAsc();
+ render();
+
apiRef.current.setSortModel([{ field: 'brand', sort: 'desc' }]);
expect(getColumnValues()).to.deep.equal(['Puma', 'Nike', 'Adidas']);
});
@@ -130,8 +131,8 @@ describe(' - Sorting', () => {
});
it('should allow to set multiple Sort items via apiRef', () => {
- renderBrandSortedAsc();
- expect(getColumnValues()).to.deep.equal(['Adidas', 'Nike', 'Puma']);
+ render();
+
const sortModel: GridSortModel = [
{ field: 'year', sort: 'desc' },
{ field: 'brand', sort: 'asc' },
@@ -144,7 +145,8 @@ describe(' - Sorting', () => {
describe('multi-sorting', () => {
['shiftKey', 'metaKey', 'ctrlKey'].forEach((key) => {
it(`should do a multi-sorting when clicking the header cell while ${key} is pressed`, () => {
- render();
+ render();
+ apiRef.current.setSortModel([{ field: 'year', sort: 'desc' }]);
expect(getColumnValues()).to.deep.equal(['Puma', 'Nike', 'Adidas']);
fireEvent.click(getColumnHeaderCell(0), { [key]: true });
expect(getColumnValues()).to.deep.equal(['Puma', 'Adidas', 'Nike']);
@@ -153,7 +155,8 @@ describe(' - Sorting', () => {
['metaKey', 'ctrlKey'].forEach((key) => {
it(`should do nothing when pressing Enter while ${key} is pressed`, () => {
- render();
+ render();
+ apiRef.current.setSortModel([{ field: 'year', sort: 'desc' }]);
expect(getColumnValues()).to.deep.equal(['Puma', 'Nike', 'Adidas']);
getColumnHeaderCell(1).focus();
fireEvent.keyDown(getColumnHeaderCell(1), { key: 'Enter', [key]: true });
@@ -162,7 +165,8 @@ describe(' - Sorting', () => {
});
it('should do a multi-sorting pressing Enter while shiftKey is pressed', () => {
- render();
+ render();
+ apiRef.current.setSortModel([{ field: 'year', sort: 'desc' }]);
expect(getColumnValues()).to.deep.equal(['Puma', 'Nike', 'Adidas']);
getColumnHeaderCell(0).focus();
fireEvent.keyDown(getColumnHeaderCell(0), { key: 'Enter', shiftKey: true });
@@ -170,16 +174,16 @@ describe(' - Sorting', () => {
});
it(`should not do a multi-sorting if no multiple key is pressed`, () => {
- render();
+ render();
+ apiRef.current.setSortModel([{ field: 'year', sort: 'desc' }]);
expect(getColumnValues()).to.deep.equal(['Puma', 'Nike', 'Adidas']);
fireEvent.click(getColumnHeaderCell(0));
expect(getColumnValues()).to.deep.equal(['Adidas', 'Nike', 'Puma']);
});
it('should not do a multi-sorting if disableMultipleColumnsSorting is true', () => {
- render(
- ,
- );
+ render();
+ apiRef.current.setSortModel([{ field: 'year', sort: 'desc' }]);
expect(getColumnValues()).to.deep.equal(['Puma', 'Nike', 'Adidas']);
fireEvent.click(getColumnHeaderCell(0), { shiftKey: true });
expect(getColumnValues()).to.deep.equal(['Adidas', 'Nike', 'Puma']);
@@ -264,4 +268,60 @@ describe(' - Sorting', () => {
setProps({ extra: true });
expect(renderCellCount).to.equal(2);
});
+
+ describe('control Sorting', () => {
+ it('should update the sorting state when neither the model nor the onChange are set', () => {
+ render();
+ expect(getColumnValues()).to.deep.equal(['Nike', 'Adidas', 'Puma']);
+ fireEvent.click(getColumnHeaderCell(0));
+ expect(getColumnValues()).to.deep.equal(['Adidas', 'Nike', 'Puma']);
+ });
+
+ it('should not update the sort model when the sortModelProp is set', () => {
+ const testSortModel: GridSortModel = [{ field: 'brand', sort: 'desc' }];
+ render();
+ expect(getColumnValues()).to.deep.equal(['Puma', 'Nike', 'Adidas']);
+ fireEvent.click(getColumnHeaderCell(0));
+ expect(getColumnValues()).to.deep.equal(['Puma', 'Nike', 'Adidas']);
+ });
+
+ it('should update the sort state when the model is not set, but the onChange is set', () => {
+ const onModelChange = spy();
+ render();
+ expect(onModelChange.callCount).to.equal(0);
+ fireEvent.click(getColumnHeaderCell(0));
+ expect(onModelChange.callCount).to.equal(1);
+ expect(onModelChange.lastCall.firstArg).to.deep.equal([{ field: 'brand', sort: 'asc' }]);
+ });
+
+ it('should control sort state when the model and the onChange are set', () => {
+ let expectedModel: GridSortModel = [];
+ const ControlCase = (props: Partial) => {
+ const { rows, columns, ...others } = props;
+ const [caseSortModel, setSortModel] = React.useState([]);
+ const handleSortChange = (newModel) => {
+ setSortModel(newModel);
+ expectedModel = newModel;
+ };
+
+ return (
+
+
+
+ );
+ };
+
+ render();
+ fireEvent.click(getColumnHeaderCell(0));
+ expect(getColumnValues()).to.deep.equal(['Adidas', 'Nike', 'Puma']);
+ expect(expectedModel).to.deep.equal([{ field: 'brand', sort: 'asc' }]);
+ });
+ });
});
diff --git a/packages/storybook/src/stories/grid-sorting.stories.tsx b/packages/storybook/src/stories/grid-sorting.stories.tsx
index 81b1823c03ad1..7c3ff952d964c 100644
--- a/packages/storybook/src/stories/grid-sorting.stories.tsx
+++ b/packages/storybook/src/stories/grid-sorting.stories.tsx
@@ -5,9 +5,9 @@ import {
GridColDef,
XGrid,
GridRowsProp,
- GridSortModelParams,
GridSortModel,
useGridApiRef,
+ getInitialGridSortingState,
} from '@material-ui/x-grid';
import { action } from '@storybook/addon-actions';
@@ -426,21 +426,25 @@ export const SortedEventsOptions = () => {
);
};
-function sortServerRows(rows: Readonly, params: GridSortModelParams): Promise {
+function sortServerRows(
+ rows: Readonly,
+ sortModel: GridSortModel,
+ columns: GridColDef[],
+): Promise {
return new Promise((resolve) => {
setTimeout(() => {
- if (params.sortModel.length === 0) {
+ if (sortModel.length === 0) {
resolve(getRows());
return;
}
- const sortedCol = params.sortModel[0];
- const comparator = params.columns[0].sortComparator!;
+ const sortedCol = sortModel[0];
+ const comparator = columns.find((col) => col.field === sortedCol.field)!.sortComparator!;
const clonedRows = [...rows];
let sortedRows = clonedRows.sort((a, b) =>
comparator(a[sortedCol.field], b[sortedCol.field], a, b),
);
- if (params.sortModel[0].sort === 'desc') {
+ if (sortModel[0].sort === 'desc') {
sortedRows = sortedRows.reverse();
}
@@ -450,28 +454,29 @@ function sortServerRows(rows: Readonly, params: GridSortModelParams): Pro
}
export const ServerSideSorting = () => {
+ const apiRef = useGridApiRef();
const [rows, setRows] = React.useState(getRows());
+ const [sortModel, setSortModel] = React.useState([{ field: 'age', sort: 'desc' }]);
const [columns] = React.useState(getColumns());
const [loading, setLoading] = React.useState(false);
const onSortModelChange = React.useCallback(
- async (params: GridSortModelParams) => {
+ async (model: GridSortModel) => {
setLoading(true);
- action('onSortModelChange')(params);
+ action('onSortModelChange')(model);
- const newRows = await sortServerRows(rows, params);
+ setSortModel(model);
+ const newRows = await sortServerRows(rows, model, apiRef.current.getVisibleColumns());
setRows(newRows);
setLoading(false);
},
- [rows],
+ [apiRef, rows],
);
- // We use `useMemo` here, to keep the same ref and not trigger another sort on the next rendering
- const sortModel: GridSortModel = React.useMemo(() => [{ field: 'age', sort: 'desc' }], []);
-
return (
{
);
};
+
+export function SimpleModelWithOnChangeControlSort() {
+ const [simpleColumns] = React.useState([
+ {
+ field: 'id',
+ },
+ { field: 'name' },
+ ]);
+ const [simpleRows] = React.useState([
+ {
+ id: '1',
+ name: 'Paris',
+ },
+ {
+ id: '2',
+ name: 'Nice',
+ },
+ {
+ id: '3',
+ name: 'London',
+ },
+ ]);
+
+ const [simpleSortModel, setSortModel] = React.useState(
+ getInitialGridSortingState().sortModel,
+ );
+ const handleSortChange = React.useCallback((model) => {
+ setSortModel(model);
+ }, []);
+
+ return (
+
+ );
+}
+export function SimpleModelControlSort() {
+ const [simpleColumns] = React.useState([
+ {
+ field: 'id',
+ },
+ { field: 'name' },
+ ]);
+ const [simpleRows] = React.useState([
+ {
+ id: '1',
+ name: 'Paris',
+ },
+ {
+ id: '2',
+ name: 'Nice',
+ },
+ {
+ id: '3',
+ name: 'London',
+ },
+ ]);
+
+ const [simpleSortModel] = React.useState([{ field: 'name', sort: 'desc' }]);
+
+ return ;
+}
+export function SimpleOnChangeControlSort() {
+ const [simpleColumns] = React.useState([
+ {
+ field: 'id',
+ },
+ { field: 'name' },
+ ]);
+ const [simpleRows] = React.useState([
+ {
+ id: '1',
+ name: 'Paris',
+ },
+ {
+ id: '2',
+ name: 'Nice',
+ },
+ {
+ id: '3',
+ name: 'London',
+ },
+ ]);
+
+ const handleSortChange = React.useCallback((model) => {
+ // eslint-disable-next-line no-console
+ console.log('Sort model changed to', model);
+ }, []);
+
+ return ;
+}