Editing
react-bootstrap-data-grid provides an opinionated interface to edit entire rows of cells at a time.
When enabled, controls to start editing, cancel editing, save changes, and delete rows are provided in special Edit Controls table column.
When the user starts editing a row by pushing the Edit button, the contents of the cells for that row turn into form inputs.
Editing is enabled by passing an editModel prop to the Grid component. One can additionally enable deletion by passing an optional getDeleteCallback member inside the editModel.
It is the responsibility of the parent component that contains the Grid to provide callback functions that actually act upon user interactions with the UI to edit or delete a row. In addition, it is the responsibility of the parent component to provide some kind of safeguard against accidental deletions (such as a confirmation dialog.)
Since null values are not supported by react-bootstrap-data-grid for now, for a row to be updated successfully, there should be a valid value for number, date, and datetime fields. For these three column types, the Grid will invoke a form validation error (using the form validation feature of the browser) when trying to use a blank string to update a field of one of these types.
However, since a blank string ("") is a valid string, the Grid will accept blank strings as input for string columns.
Type Definitions
EditModel
Omitting this prop from the Grid component disables the editing feature.
| Property name | Type definition | Required/Optional | Description |
|---|---|---|---|
| getUpdateCallback | UpdateCallbackGenerator | Required | A function that takes the id of a row and returns a callback function for updating a row. |
| getDeleteCallback | (id: RowId) => () => void | Optional | A function takes the original index of a row and returns a callback function for deleting the row. Omitting this property disables the UI for deletions. |
UpdateCallbackGenerator
This type is that of the function passed into EditModel for generating a callback function on a per-index basis. The defintion is {"(id: RowId) => (rowDef: RowData) => void"}.
See the example below to see how this property is typically implemented.
Example
Code
"use client";
import Grid, {
ColDef,
UpdateCallbackGenerator,
RowDef,
RowId,
} from "@absreim/react-bootstrap-data-grid";
import { FC, useState } from "react";
const cols: ColDef[] = [
{
name: "name",
type: "string",
label: "Name",
},
{
name: "class",
type: "string",
label: "Class",
},
{
name: "selectionPriority",
type: "number",
label: "Selection Priority",
},
{
name: "recruitmentDate",
type: "date",
label: "Recruitment Date",
},
];
interface Data {
name: string;
class: string;
selectionPriority: number;
recruitmentDate: Date;
}
const initRows: RowDef<Data>[] = [
{
id: 0,
data: {
name: "Astarion",
class: "Rogue",
selectionPriority: 1,
recruitmentDate: new Date("2023-10-02"),
},
},
{
id: 1,
data: {
name: "Lae'zel",
class: "Fighter",
selectionPriority: 4,
recruitmentDate: new Date("2023-09-30"),
},
},
{
id: 2,
data: {
name: "Shadowheart",
class: "Cleric",
selectionPriority: 2,
recruitmentDate: new Date("2023-10-01"),
},
},
{
id: 3,
data: {
name: "Dark Urge",
class: "Sorcerer",
selectionPriority: 5,
recruitmentDate: new Date("2023-09-29"),
},
},
{
id: 4,
data: {
name: "Gale",
class: "Wizard",
selectionPriority: 3,
recruitmentDate: new Date("2023-10-03"),
},
},
{
id: 5,
data: {
name: "Wyll",
class: "Warlock",
selectionPriority: 5,
recruitmentDate: new Date("2023-10-04"),
},
},
{
id: 6,
data: {
name: "Karlach",
class: "Barbarian",
selectionPriority: 4,
recruitmentDate: new Date("2023-10-05"),
},
},
{
id: 7,
data: {
name: "Minthara",
class: "Paladin",
selectionPriority: 5,
recruitmentDate: new Date("2023-10-06"),
},
},
{
id: 8,
data: {
name: "Halsin",
class: "Druid",
selectionPriority: 4,
recruitmentDate: new Date("2023-10-07"),
},
},
{
id: 9,
data: {
name: "Jaheira",
class: "Druid",
selectionPriority: 4,
recruitmentDate: new Date("2023-10-08"),
},
},
{
id: 10,
data: {
name: "Minsc",
class: "Ranger",
selectionPriority: 2,
recruitmentDate: new Date("2023-10-09"),
},
},
];
const SampleEditableGridContainer: FC = () => {
const [rows, setRows] = useState<RowDef[]>(initRows.slice());
const getUpdateCallback: UpdateCallbackGenerator = (id) => (rowData) => {
const newRows = rows.slice();
const index = rows.findIndex((row) => row.id === id);
if (index === undefined) {
return;
}
newRows[index] = {
id,
data: rowData,
};
setRows(newRows);
};
const getDeleteCallback: (id: RowId) => () => void = (id) => () => {
if (window.confirm("Are you sure you want to delete this row?")) {
const index = rows.findIndex((row) => row.id === id);
if (index === undefined) {
return;
}
setRows(rows.toSpliced(index, 1));
}
};
return (
<Grid
rows={rows}
cols={cols}
editModel={{ getUpdateCallback, getDeleteCallback }}
caption={"Plan out your party for your BG3 adventure"}
/>
);
};
export default SampleEditableGridContainer;Live Demo
| Name | Class | Selection Priority | Recruitment Date | Edit Controls |
|---|---|---|---|---|
| Astarion | Rogue | 1 | 2023-10-02 | |
| Lae'zel | Fighter | 4 | 2023-09-30 | |
| Shadowheart | Cleric | 2 | 2023-10-01 | |
| Dark Urge | Sorcerer | 5 | 2023-09-29 | |
| Gale | Wizard | 3 | 2023-10-03 | |
| Wyll | Warlock | 5 | 2023-10-04 | |
| Karlach | Barbarian | 4 | 2023-10-05 | |
| Minthara | Paladin | 5 | 2023-10-06 | |
| Halsin | Druid | 4 | 2023-10-07 | |
| Jaheira | Druid | 4 | 2023-10-08 | |
| Minsc | Ranger | 2 | 2023-10-09 |