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

[XGrid] Add ability to disable reorder on some columns #2085

Merged
merged 15 commits into from
Jul 21, 2021
1 change: 1 addition & 0 deletions docs/pages/api-docs/data-grid/grid-col-def.md
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@ import { GridColDef } from '@material-ui/data-grid';
| <span class="prop-name optional">cellClassName<sup><abbr title="optional">?</abbr></sup></span> | <span class="prop-type">GridCellClassNamePropType</span> | | Class name that will be added in cells for that column. |
| <span class="prop-name optional">description<sup><abbr title="optional">?</abbr></sup></span> | <span class="prop-type">string</span> | | The description of the column rendered as tooltip if the column header name is not fully displayed. |
| <span class="prop-name optional">disableColumnMenu<sup><abbr title="optional">?</abbr></sup></span> | <span class="prop-type">boolean</span> | <span class="prop-default">false<br /></span> | If `true`, the column menu is disabled for this column. |
| <span class="prop-name optional">disableReorder<sup><abbr title="optional">?</abbr></sup></span> | <span class="prop-type">boolean</span> | <span class="prop-default">false<br /></span> | If `true`, this column can not be reordered. |
| <span class="prop-name optional">disableExport<sup><abbr title="optional">?</abbr></sup></span> | <span class="prop-type">boolean</span> | <span class="prop-default">false<br /></span> | If `true`, this column will not be included in exports. |
| <span class="prop-name optional">editable<sup><abbr title="optional">?</abbr></sup></span> | <span class="prop-type">boolean</span> | <span class="prop-default">false<br /></span> | If `true`, the cells of the column are editable. |
| <span class="prop-name">field</span> | <span class="prop-type">string</span> | | The column identifier. It's used to map with GridRowData values. |
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import * as React from 'react';
import { XGrid } from '@material-ui/x-grid';

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

export default function ColumnOrderingDisabledGrid() {
return (
<div style={{ height: 250, width: '100%' }}>
<XGrid
columns={[
{ field: 'id' },
{ field: 'username' },
{ field: 'age', disableReorder: true },
]}
rows={rows}
/>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import * as React from 'react';
import { XGrid } from '@material-ui/x-grid';

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

export default function ColumnOrderingDisabledGrid() {
return (
<div style={{ height: 250, width: '100%' }}>
<XGrid
columns={[
{ field: 'id' },
{ field: 'username' },
{ field: 'age', disableReorder: true },
]}
rows={rows}
/>
</div>
);
}
10 changes: 7 additions & 3 deletions docs/src/pages/components/data-grid/columns/columns.md
Original file line number Diff line number Diff line change
@@ -286,7 +286,13 @@ To disable the column selector, set the prop `disableColumnSelector={true}`.

By default, `XGrid` allows all column reordering by dragging the header cells and moving them left or right.

To disable column reordering, set the prop `disableColumnReorder={true}`.
{{"demo": "pages/components/data-grid/columns/ColumnOrderingGrid.js", "disableAd": true, "bg": "inline"}}

To disable reordering on all columns, set the prop `disableColumnReorder={true}`.

To disable reordering on some columns, set the `disableReorder` property of the column definition `GridColDef` object to `true`.
flaviendelangle marked this conversation as resolved.
Show resolved Hide resolved

{{"demo": "pages/components/data-grid/columns/ColumnOrderingDisabledGrid.js", "disableAd": true, "bg": "inline"}}

In addition, column reordering emits the following events that can be imported:

@@ -295,8 +301,6 @@ In addition, column reordering emits the following events that can be imported:
- `columnHeaderDragOver`: emitted when dragging a header cell over another header cell.
- `columnHeaderDragEnd`: emitted when dragging of a header cell stops.

{{"demo": "pages/components/data-grid/columns/ColumnOrderingGrid.js", "disableAd": true, "bg": "inline"}}

## 🚧 Column groups

> ⚠️ This feature isn't implemented yet. It's coming.
Original file line number Diff line number Diff line change
@@ -208,7 +208,7 @@ export function GridColumnHeaderItem(props: GridColumnHeaderItemProps) {
>
<div
className="MuiDataGrid-columnHeaderDraggableContainer"
draggable={!disableColumnReorder}
draggable={!disableColumnReorder && !column.disableReorder}
{...draggableEventHandlers}
>
<div className="MuiDataGrid-columnHeaderTitleContainer">
Original file line number Diff line number Diff line change
@@ -42,7 +42,7 @@ export const useGridColumnReorder = (apiRef: GridApiRef): void => {
const logger = useLogger('useGridColumnReorder');

const [, setGridState, forceUpdate] = useGridState(apiRef);
const dragCol = useGridSelector(apiRef, gridColumnReorderDragColSelector);
const dragColField = useGridSelector(apiRef, gridColumnReorderDragColSelector);
const options = useGridSelector(apiRef, optionsSelector);
const dragColNode = React.useRef<HTMLElement | null>(null);
const cursorPosition = React.useRef<CursorCoordinates>({
@@ -60,7 +60,7 @@ export const useGridColumnReorder = (apiRef: GridApiRef): void => {

const handleColumnHeaderDragStart = React.useCallback(
(params: GridColumnHeaderParams, event: React.MouseEvent<HTMLElement>) => {
if (options.disableColumnReorder) {
if (options.disableColumnReorder || params.colDef.disableReorder) {
return;
}

@@ -93,7 +93,7 @@ export const useGridColumnReorder = (apiRef: GridApiRef): void => {

const handleDragOver = React.useCallback(
(params: GridColumnHeaderParams | GridCellParams, event: React.DragEvent) => {
if (!dragCol) {
if (!dragColField) {
return;
}

@@ -103,27 +103,33 @@ export const useGridColumnReorder = (apiRef: GridApiRef): void => {
const coordinates = { x: event.clientX, y: event.clientY };

if (
params.field !== dragCol &&
params.field !== dragColField &&
hasCursorPositionChanged(cursorPosition.current, coordinates)
) {
const targetColIndex = apiRef.current.getColumnIndex(params.field, false);
const dragColIndex = apiRef.current.getColumnIndex(dragCol, false);

if (
(getCursorMoveDirectionX(cursorPosition.current, coordinates) ===
CURSOR_MOVE_DIRECTION_RIGHT &&
dragColIndex < targetColIndex) ||
(getCursorMoveDirectionX(cursorPosition.current, coordinates) ===
CURSOR_MOVE_DIRECTION_LEFT &&
targetColIndex < dragColIndex)
) {
apiRef.current.setColumnIndex(dragCol, targetColIndex);
const targetColVisibleIndex = apiRef.current.getColumnIndex(params.field, true);
const targetCol = apiRef.current.getColumn(params.field);
const dragColIndex = apiRef.current.getColumnIndex(dragColField, false);
const visibleColumnAmount = apiRef.current.getVisibleColumns().length;

const canBeReordered =
!targetCol.disableReorder ||
(targetColVisibleIndex > 0 && targetColVisibleIndex < visibleColumnAmount - 1);

const cursorMoveDirectionX = getCursorMoveDirectionX(cursorPosition.current, coordinates);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For another PR:

This cursorMoveDirectionX is wrong. It's always "right" the first time. We need to save the cursor position when the user starts dragging

const hasMovedLeft =
cursorMoveDirectionX === CURSOR_MOVE_DIRECTION_LEFT && targetColIndex < dragColIndex;
const hasMovedRight =
cursorMoveDirectionX === CURSOR_MOVE_DIRECTION_RIGHT && dragColIndex < targetColIndex;

if (canBeReordered && (hasMovedLeft || hasMovedRight)) {
apiRef.current.setColumnIndex(dragColField, targetColIndex);
}

cursorPosition.current = coordinates;
}
},
[apiRef, dragCol, logger],
[apiRef, dragColField, logger],
);

const handleDragEnd = React.useCallback(
flaviendelangle marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -144,8 +144,8 @@ export function useGridColumns(apiRef: GridApiRef, { columns }: { columns: GridC
const getVisibleColumns = React.useCallback(() => visibleColumns, [visibleColumns]);
const getColumnsMeta: () => GridColumnsMeta = React.useCallback(() => columnsMeta, [columnsMeta]);

const getColumnIndex: (field: string, useVisibleColumns?: boolean) => number = React.useCallback(
(field, useVisibleColumns = true) =>
const getColumnIndex = React.useCallback(
(field: string, useVisibleColumns: boolean = true): number =>
useVisibleColumns
? visibleColumns.findIndex((col) => col.field === field)
: allColumns.findIndex((col) => col.field === field),
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@ export const gridCheckboxSelectionColDef: GridColDef = {
sortable: false,
filterable: false,
disableColumnMenu: true,
disableReorder: true,
valueGetter: (params) => {
const selectionLookup = selectedIdsLookupSelector(params.api.getState());
return selectionLookup[params.id] !== undefined;
5 changes: 5 additions & 0 deletions packages/grid/_modules_/grid/models/colDef/gridColDef.ts
Original file line number Diff line number Diff line change
@@ -143,6 +143,11 @@ export interface GridColDef {
* Allows setting the filter operators for this column.
*/
filterOperators?: GridFilterOperator[];
/**
* If `true`, this column can not be reordered.
flaviendelangle marked this conversation as resolved.
Show resolved Hide resolved
* @default false
*/
disableReorder?: boolean;
/**
* If `true`, this column will not be included in exports.
* @default false
Loading