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 nameType definitionRequired/OptionalDescription
getUpdateCallbackUpdateCallbackGeneratorRequiredA function that takes the id of a row and returns a callback function for updating a row.
getDeleteCallback(id: RowId) => () => voidOptionalA 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

Plan out your party for your BG3 adventure
NameClassSelection PriorityRecruitment DateEdit Controls
AstarionRogue12023-10-02
Lae'zelFighter42023-09-30
ShadowheartCleric22023-10-01
Dark UrgeSorcerer52023-09-29
GaleWizard32023-10-03
WyllWarlock52023-10-04
KarlachBarbarian42023-10-05
MintharaPaladin52023-10-06
HalsinDruid42023-10-07
JaheiraDruid42023-10-08
MinscRanger22023-10-09