Column and row reordering
How to implement column and row reordering?
This guide is based on getting started .
1. Update person interface and people data
Our Person interface will be extended with the id field. It’s necessary to identify person to keep correct order after
row reorder action.
interface Person {
id: number;
name: string;
surname: string;
}
const getPeople = (): Person[] => [
{ id: 1, name: "Thomas", surname: "Goldman" },
{ id: 2, name: "Susie", surname: "Quattro" },
{ id: 3, name: "", surname: "" }
];2. Update column related properties
In our example we will be able to see how to reorder two declared columns. We are currenly working with a column whose application we know everything about. Let’s define coresponding interface that is personalized stricly to our needs.
interface ColumnMap {
name: 'Name';
surname: 'Surname';
}
const columnMap: ColumnMap = {
name: 'Name',
surname: 'Surname'
};ReactGrid’s Column interface contains columnId property. You can assign any string or even numberto this property.
In this example we know that we are working with only name and surname as so we can augment Column
interface definition by doing this:
type ColumnId = keyof ColumnMap;3. Make your columns reorderable
This step is simple - just add reorderable: true to the column definitions.
const getColumns = (): Column[] => [
{ columnId: 'name', width: 150, reorderable: true }, { columnId: 'surname', width: 200, reorderable: true }];4. Display rows with arbitrary columns order
In Relation to the base example we need to add one mode argument: columnsOrder.
This parameter contains columns key (name or surname) in the same order as we want to display people.
We also moved headerRow and replaced it with an object to get a corresponding column title and value of columnMap.
Also cells inside mapped people array select persons’ attributes in accordance with the order of columns.
const getRows = (people: Person[], columnsOrder: ColumnId[]): Row[] => {
return [
{
rowId: "header",
cells: [
{ type: "header", text: columnMap[columnsOrder[0]] },
{ type: "header", text: columnMap[columnsOrder[1]] }
]
},
...people.map<Row>((person, idx) => ({
rowId: person.id,
reorderable: true,
cells: [
{ type: "text", text: person[columnsOrder[0]] }, // `person['name']` / `person['surname']`
{ type: "text", text: person[columnsOrder[1]] } // `person['surname']` / `person['name']`
]
}))
]
};reorderArray function is used to order columns or rows. You can just copy it.
// a helper function used to reorder arbitrary arrays
const reorderArray = <T extends {}>(arr: T[], idxs: number[], to: number) => {
const movedElements = arr.filter((_, idx) => idxs.includes(idx));
const targetIdx = Math.min(...idxs) < to ? to += 1 : to -= idxs.filter(idx => idx < to).length;
const leftSide = arr.filter((_, idx) => idx < targetIdx && !idxs.includes(idx));
const rightSide = arr.filter((_, idx) => idx >= targetIdx && !idxs.includes(idx));
return [...leftSide, ...movedElements, ...rightSide];
}5. Implement column and row handlers
All that remains to write is handler for rows and column reordering.
Column and row reorder handler is based on searching for destination target index and mapping reordered items to array
of their occurrence. After that we pass previously mentioned indexes to reorderArray function and update data by calling
setColumns and setPeople.
ReactGrid component needs to have enabled enableRowSelection and enableColumnSelection.
const ColumnsAndRowsReorderSample = () => {
const [people, setPeople] = React.useState<Person[]>(getPeople());
const [columns, setColumns] = React.useState<Column[]>(getColumns());
const rows = getRows(people, columns.map(c => c.columnId as ColumnId));
const handleColumnsReorder = (targetColumnId: Id, columnIds: Id[]) => {
const to = columns.findIndex((column) => column.columnId === targetColumnId);
const columnIdxs = columnIds.map((columnId) => columns.findIndex((c) => c.columnId === columnId));
setColumns(prevColumns => reorderArray(prevColumns, columnIdxs, to));
}
const handleRowsReorder = (targetRowId: Id, rowIds: Id[]) => {
setPeople((prevPeople) => {
const to = people.findIndex(person => person.id === targetRowId);
const rowsIds = rowIds.map((id) => people.findIndex(person => person.id === id));
return reorderArray(prevPeople, rowsIds, to);
});
}
return <ReactGrid
rows={rows}
columns={columns}
onColumnsReordered={handleColumnsReorder}
onRowsReordered={handleRowsReorder}
enableRowSelection
enableColumnSelection
/>;
}Bonus - preventing dropping rows on unwanted location
This ‘feature’ can be done by making handleCanReorderRows function and passing it to canReorderRows ReactGrid prop.
We also provided canReorderColumns prop that can do the same thing, but with columns.
While you reorder a row you can see the line that is visible above the header row. We probably don’t want to mislead the end user who might drop the row over there.
When you drop row then your handleCanReorderRows is called. We can define that dropping over the row whose rowId field equals
header is prohibited. In this case you won’t see reorder line indication and handleRowsReorder is not called by default.
const handleCanReorderRows = (targetRowId: Id, rowIds: Id[]): boolean => {
return targetRowId !== 'header';
}const ColumnsAndRowsReorderSample = () => {
// ...
return <ReactGrid
rows={rows}
columns={columns}
onColumnsReordered={handleColumnsReorder}
onRowsReordered={handleRowsReorder}
enableRowSelection
enableColumnSelection
canReorderRows={handleCanReorderRows} />;
}