Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DataGrid] Add a recipe to persist column width and order #14560

Merged
merged 14 commits into from
Nov 7, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import * as React from 'react';
import {
DataGridPro,
useGridApiRef,
gridColumnFieldsSelector,
} from '@mui/x-data-grid-pro';
import Button from '@mui/material/Button';

const rows = [
{
id: 1,
username: '@MUI',
age: 20,
},
];

const useColumnsState = (apiRef, columns) => {
const [widths, setWidths] = React.useState({});
const [orderedFields, setOrderedFields] = React.useState(
columns.map((column) => column.field),
);
MBilalShafi marked this conversation as resolved.
Show resolved Hide resolved

const onColumnWidthChange = React.useCallback(
({ colDef, width }) => {
setWidths((prev) => ({ ...prev, [colDef.field]: width }));
},
[setWidths],
);

const onColumnOrderChange = React.useCallback(() => {
setOrderedFields(gridColumnFieldsSelector(apiRef));
}, [apiRef, setOrderedFields]);

const computedColumns = React.useMemo(
() =>
orderedFields.reduce((acc, field) => {
const column = columns.find((col) => col.field === field);
if (!column) {
return acc;
}
if (widths[field]) {
acc.push({
...column,
width: widths[field],
});
return acc;
}
acc.push(column);
return acc;
}, []),
[columns, widths, orderedFields],
);

return { columns: computedColumns, onColumnWidthChange, onColumnOrderChange };
};

export default function ColumnSizingPersistWidthOrder() {
const apiRef = useGridApiRef();
const [index, setIndex] = React.useState(0);
const inputColumns = React.useMemo(
() => [
{ field: 'id' },
{ field: 'username', width: 200, key: index },
{ field: 'age', disableReorder: true },
],
[index],
);

const columnsState = useColumnsState(apiRef, inputColumns);

return (
<div style={{ width: '100%' }}>
<Button onClick={() => setIndex((prev) => prev + 1)}>
Update columns reference
</Button>
<div style={{ height: 250 }}>
<DataGridPro
apiRef={apiRef}
columns={columnsState.columns}
onColumnWidthChange={columnsState.onColumnWidthChange}
onColumnOrderChange={columnsState.onColumnOrderChange}
rows={rows}
/>
</div>
</div>
);
}
MBilalShafi marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import * as React from 'react';
import {
DataGridPro,
useGridApiRef,
GridColDef,
GridColumnResizeParams,
gridColumnFieldsSelector,
GridApiPro,
} from '@mui/x-data-grid-pro';
import Button from '@mui/material/Button';

const rows = [
{
id: 1,
username: '@MUI',
age: 20,
},
];

const useColumnsState = (
apiRef: React.MutableRefObject<GridApiPro>,
columns: GridColDef[],
) => {
const [widths, setWidths] = React.useState<Record<GridColDef['field'], number>>(
{},
);
const [orderedFields, setOrderedFields] = React.useState<GridColDef['field'][]>(
columns.map((column) => column.field),
);

const onColumnWidthChange = React.useCallback(
({ colDef, width }: GridColumnResizeParams) => {
setWidths((prev) => ({ ...prev, [colDef.field]: width }));
},
[setWidths],
);

const onColumnOrderChange = React.useCallback(() => {
setOrderedFields(gridColumnFieldsSelector(apiRef));
}, [apiRef, setOrderedFields]);

const computedColumns = React.useMemo(
() =>
orderedFields.reduce<GridColDef[]>((acc, field) => {
const column = columns.find((col) => col.field === field);
if (!column) {
return acc;
}
if (widths[field]) {
acc.push({
...column,
width: widths[field],
});
return acc;
}
acc.push(column);
return acc;
}, []),
[columns, widths, orderedFields],
);

return { columns: computedColumns, onColumnWidthChange, onColumnOrderChange };
};

export default function ColumnSizingPersistWidthOrder() {
const apiRef = useGridApiRef();
const [index, setIndex] = React.useState(0);
const inputColumns = React.useMemo(
() => [
{ field: 'id' },
{ field: 'username', width: 200, key: index },
{ field: 'age', disableReorder: true },
],
[index],
);

const columnsState = useColumnsState(apiRef, inputColumns);

return (
<div style={{ width: '100%' }}>
<Button onClick={() => setIndex((prev) => prev + 1)}>
Update columns reference
</Button>
<div style={{ height: 250 }}>
<DataGridPro
apiRef={apiRef}
columns={columnsState.columns}
onColumnWidthChange={columnsState.onColumnWidthChange}
onColumnOrderChange={columnsState.onColumnOrderChange}
rows={rows}
/>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Button onClick={() => setIndex((prev) => prev + 1)}>
Update columns reference
</Button>
<div style={{ height: 250 }}>
<DataGridPro
apiRef={apiRef}
columns={columnsState.columns}
onColumnWidthChange={columnsState.onColumnWidthChange}
onColumnOrderChange={columnsState.onColumnOrderChange}
rows={rows}
/>
</div>
20 changes: 20 additions & 0 deletions docs/data/data-grid/column-recipes/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
title: Data Grid - Column recipes
---

# Data Grid - Column customization recipes

<p class="description">Advanced column customization recipes.</p>

## Persisting column width and order

When the `columns` prop reference is updated, the column width and order is reset to the `colDef.width` and the order of the `colDef` object and any updates will be lost.

Check warning on line 11 in docs/data/data-grid/column-recipes/index.md

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Google.Will] Avoid using 'will'. Raw Output: {"message": "[Google.Will] Avoid using 'will'.", "location": {"path": "docs/data/data-grid/column-recipes/index.md", "range": {"start": {"line": 11, "column": 158}}}, "severity": "WARNING"}
This is because the Data Grid considers update of the columns prop as a new set of columns, and the previous state is discarded.

To persist the column width and order when the `columns` prop is updated, consider persisting the state of the columns in the userland.

{{"demo": "ColumnSizingPersistWidthOrder.js", "disableAd": true, "bg": "inline"}}

:::warning
[Column ordering](/x/react-data-grid/column-ordering/) is a Pro feature, to use it you must be on a Pro or Premium plan.
:::
1 change: 1 addition & 0 deletions docs/data/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const pages: MuiPage[] = [
{ pathname: '/x/react-data-grid/column-groups' },
{ pathname: '/x/react-data-grid/column-ordering', plan: 'pro' },
{ pathname: '/x/react-data-grid/column-pinning', plan: 'pro' },
{ pathname: '/x/react-data-grid/column-recipes', title: 'Recipes' },
],
},
{
Expand Down
7 changes: 7 additions & 0 deletions docs/pages/x/react-data-grid/column-recipes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as React from 'react';
import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs';
import * as pageProps from 'docsx/data/data-grid/column-recipes/index.md?muiMarkdown';

export default function Page() {
return <MarkdownDocs {...pageProps} />;
}
Loading