How to implement column and row reordering?
💡
This feature is only available in PRO version
This guide is based on getting started.
1. Add some new imports for further usage
We'll need Id
, DropPosition
,
Column
and Row
.
import { ReactGrid, Id, DropPosition, Column, Row } from "@silevis/reactgrid"; //highlight-line
2. Modify the rows and columns to enable reordering
This is done by adding the reorderable
property to a column or row and setting its value to true
.
const [columns, setColumns] = React.useState<Column[]>(() => [
{ columnId: "Name", width: 100, reorderable: true }, //highlight-line
{ columnId: "Surname", width: 100, reorderable: true } //highlight-line
]);
Notice that we don't want the first row to be reorderable because that's our grid's header so the reorderable
property will become undefined
contrary to other rows.
const [rows, setRows] = React.useState<Row[]>(() => [
{
rowId: 0,
reorderable: true, //highlight-line
cells: [
{ type: "header", text: "Name" },
{ type: "header", text: "Surname" }
]
},
{
rowId: 1,
reorderable: true, //highlight-line
cells: [
{ type: "text", text: "Thomas" },
{ type: "text", text: "Goldman" }
]
},
{
rowId: 2,
reorderable: true, //highlight-line
cells: [
{ type: "text", text: "Susie" },
{ type: "text", text: "Spencer" }
]
},
{
rowId: 3,
reorderable: true, //highlight-line
cells: [
{ type: "text", text: "" },
{ type: "text", text: "" }
]
}
]);
3. Implement the handler functions
reorderArray
function is used to order columns or rows.
// a helper function used to reorder arbitrary arrays
const reorderArray = <T extends {}>(arr: T[], idxs: number[], to: number) => {
const movedElements: T[] = arr.filter((_: T, idx: number) => idxs.includes(idx));
to = Math.min(...idxs) < to ? to += 1 : to -= idxs.filter(idx => idx < to).length;
const leftSide: T[] = arr.filter((_: T, idx: number) => idx < to && !idxs.includes(idx));
const rightSide: T[] = arr.filter((_: T, idx: number) => idx >= to && !idxs.includes(idx));
return [...leftSide, ...movedElements, ...rightSide];
}
const handleColumnsReorder = (targetColumnId: Id, columnIds: Id[], dropPosition: DropPosition) => {
const to = columns.findIndex((column: Column) => column.columnId === targetColumnId);
const columnIdxs = columnIds.map((id: Id, idx: number) => columns.findIndex((c: Column) => c.columnId === id));
setRows(rows.map(row => ({ ...row, cells: reorderArray(row.cells, columnIdxs, to) })));
setColumns(reorderArray(columns, columnIdxs, to));
}
const handleRowsReorder = (targetRowId: Id, rowIds: Id[], dropPosition: DropPosition) => {
setRows((prevRows) => {
const to = rows.findIndex(row => row.rowId === targetRowId);
const columnIdxs = rowIds.map(id => rows.findIndex(r => r.rowId === id));
return reorderArray(prevRows, columnIdxs, to);
});
}
- Pass the handler functions to your
ReactGrid
component and addenableRowSelection
andenableColumnSelection
properties to enable this type of events handling.
<ReactGrid
rows={rows}
columns={columns}
onColumnsReordered={handleColumnsReordered} // highlight-line
onRowsReordered={handleRowsReordered} // highlight-line
enableRowSelection // highlight-line
enableColumnSelection // highlight-line
/>
Live demo
Code
const ColumnsAndRowsReorderSample = () => { const [columns, setColumns] = React.useState<Column[]>(() => [ { columnId: "Name", width: 100, reorderable: true }, { columnId: "Surname", width: 100, reorderable: true } ]); const [rows, setRows] = React.useState<Row[]>(() => [ { rowId: 0, reorderable: true, cells: [ { type: "header", text: "Name" }, { type: "header", text: "Surname" } ] }, { rowId: 1, reorderable: true, cells: [ { type: "text", text: "Thomas" }, { type: "text", text: "Goldman" } ] }, { rowId: 2, reorderable: true, cells: [ { type: "text", text: "Susie" }, { type: "text", text: "Spencer" } ] }, { rowId: 3, reorderable: true, cells: [ { type: "text", text: "" }, { type: "text", text: "" } ] } ]); const reorderArray = <T extends {}>(arr: T[], idxs: number[], to: number) => { const movedElements: T[] = arr.filter((_: T, idx: number) => idxs.includes(idx)); to = Math.min(...idxs) < to ? to += 1 : to -= idxs.filter(idx => idx < to).length; const leftSide: T[] = arr.filter((_: T, idx: number) => idx < to && !idxs.includes(idx)); const rightSide: T[] = arr.filter((_: T, idx: number) => idx >= to && !idxs.includes(idx)); return [...leftSide, ...movedElements, ...rightSide]; } const handleColumnsReorder = (targetColumnId: Id, columnIds: Id[], dropPosition: DropPosition) => { const to = columns.findIndex((column: Column) => column.columnId === targetColumnId); const columnIdxs = columnIds.map((id: Id, idx: number) => columns.findIndex((c: Column) => c.columnId === id)); setRows(rows.map(row => ({ ...row, cells: reorderArray(row.cells, columnIdxs, to) }))); setColumns(reorderArray(columns, columnIdxs, to)); } const handleRowsReorder = (targetRowId: Id, rowIds: Id[], dropPosition: DropPosition) => { setRows((prevRows) => { const to = rows.findIndex(row => row.rowId === targetRowId); const columnIdxs = rowIds.map(id => rows.findIndex(r => r.rowId === id)); return reorderArray(prevRows, columnIdxs, to); }); } const handleCanReorderColumns = (targetColumnId: Id, columnIds: Id[], dropPosition: DropPosition): boolean => { return true; } const handleCanReorderRows = (targetColumnId: Id, rowIds: Id[], dropPosition: DropPosition): boolean => { return true; } return ( <ReactGrid rows={rows} columns={columns} onColumnsReordered={handleColumnsReorder} onRowsReordered={handleRowsReorder} canReorderRows={handleCanReorderRows} canReorderColumns={handleCanReorderColumns} enableRowSelection enableColumnSelection /> ); } render(<ColumnsAndRowsReorderSample/>)
Preview