ra-editable-datagrid

The default react-admin user-experience consists of 3 pages: List, Edit, and Create. However, in some cases, users may prefer to do all search and edition tasks in one page. This package offers an "edit-in-place" experience in a <Datagrid>.

ra-editable-datagrid

Test it live in the Enterprise Edition Storybook and in the e-commerce demo.

Users can click on a row in the datagrid to replace the row with an edition form, and edit the corresponding record without leaving the list. They can also create new records by clicking on the Create button, which inserts an empty editable row as the first line of the list. Finally, they can delete a record by clicking on the Delete button on each row.

Installation

npm install --save @react-admin/ra-editable-datagrid
# or
yarn add @react-admin/ra-editable-datagrid

Tip: ra-editable-datagrid is part of the React-Admin Enterprise Edition, and hosted in a private npm registry. You need to subscribe to one of the Enterprise Edition plans to access this package.

Usage

Use <EditableDatagrid> as a child of a react-admin <List> or <ReferenceManyField>, in replacement of a <Datagrid>. In addition, pass a form component to be displayed when the user switches to edit or create mode.

import React from "react";
import {
  List,
  ListProps,
  TextField,
  TextInput,
  DateField,
  DateInput,
  SelectField,
  SelectInput,
  required,
} from "react-admin";
import {
  EditableDatagrid,
  RowForm,
  RowFormProps,
} from "@react-admin/ra-editable-datagrid";

const ArtistList = (props: ListProps) => (
  <List {...props} hasCreate empty={false}>
    <EditableDatagrid
      undoable
      createForm={<ArtistForm />}
      editForm={<ArtistForm />}
    >
      <TextField source="id" />
      <TextField source="firstname" />
      <TextField source="name" />
      <DateField source="dob" label="born" />
      <SelectField
        source="prof"
        label="Profession"
        choices={professionChoices}
      />
    </EditableDatagrid>
  </List>
);

const ArtistForm = (props: RowFormProps) => (
  <RowForm {...props}>
    <TextField source="id" />
    <TextInput source="firstname" validate={required()} />
    <TextInput source="name" validate={required()} />
    <DateInput source="dob" label="born" validate={required()} />
    <SelectInput source="prof" label="Profession" choices={professionChoices} />
  </RowForm>
);
import React from "react";
import {
  List,
  TextField,
  TextInput,
  DateField,
  DateInput,
  SelectField,
  SelectInput,
  required,
} from "react-admin";
import { EditableDatagrid, RowForm } from "@react-admin/ra-editable-datagrid";

const ArtistList = (props) => (
  <List {...props} hasCreate empty={false}>
    <EditableDatagrid
      undoable
      createForm={<ArtistForm />}
      editForm={<ArtistForm />}
    >
      <TextField source="id" />
      <TextField source="firstname" />
      <TextField source="name" />
      <DateField source="dob" label="born" />
      <SelectField
        source="prof"
        label="Profession"
        choices={professionChoices}
      />
    </EditableDatagrid>
  </List>
);

const ArtistForm = (props) => (
  <RowForm {...props}>
    <TextField source="id" />
    <TextInput source="firstname" validate={required()} />
    <TextInput source="name" validate={required()} />
    <DateInput source="dob" label="born" validate={required()} />
    <SelectInput source="prof" label="Profession" choices={professionChoices} />
  </RowForm>
);

Here is another example, this time inside a <ReferenceManyField>. The only difference with its usage in a <List> is that you have to initialize the foreign key in the create form using the initialValues prop:

import React from "react";
import {
  Edit,
  EditProps,
  SimpleForm,
  TextField,
  DateField,
  NumberField,
  ReferenceManyField,
  TextInput,
  DateInput,
  NumberInput,
  required,
} from "react-admin";
import {
  EditableDatagrid,
  RowForm,
  RowFormProps,
} from "@react-admin/ra-editable-datagrid";

const OrderEdit = ({ id, ...props }: EditProps) => (
  <Edit {...props} id={id}>
    <SimpleForm>
      <ReferenceManyField
        fullWidth
        label="Products"
        reference="products"
        target="order_id"
      >
        <EditableDatagrid
          undoable
          createForm={<ProductForm initialValues={{ order_id: id }} />}
          editForm={<ProductForm />}
          rowClick="edit"
          hasCreate
        >
          <TextField source="id" />
          <TextField source="name" />
          <NumberField source="price" label="Default Price" />
          <DateField source="available_since" />
        </EditableDatagrid>
      </ReferenceManyField>
      <DateInput source="purchase_date" />
    </SimpleForm>
  </Edit>
);

const ProductForm = (props: RowFormProps) => (
  <RowForm {...props}>
    <TextField source="id" disabled />
    <TextInput source="name" validate={required()} />
    <NumberInput source="price" label="Default Price" validate={required()} />
    <DateInput source="available_since" validate={required()} />
  </RowForm>
);
import React from "react";
import {
  Edit,
  SimpleForm,
  TextField,
  DateField,
  NumberField,
  ReferenceManyField,
  TextInput,
  DateInput,
  NumberInput,
  required,
} from "react-admin";
import { EditableDatagrid, RowForm } from "@react-admin/ra-editable-datagrid";

const OrderEdit = ({ id, ...props }) => (
  <Edit {...props} id={id}>
    <SimpleForm>
      <ReferenceManyField
        fullWidth
        label="Products"
        reference="products"
        target="order_id"
      >
        <EditableDatagrid
          undoable
          createForm={<ProductForm initialValues={{ order_id: id }} />}
          editForm={<ProductForm />}
          rowClick="edit"
          hasCreate
        >
          <TextField source="id" />
          <TextField source="name" />
          <NumberField source="price" label="Default Price" />
          <DateField source="available_since" />
        </EditableDatagrid>
      </ReferenceManyField>
      <DateInput source="purchase_date" />
    </SimpleForm>
  </Edit>
);

const ProductForm = (props) => (
  <RowForm {...props}>
    <TextField source="id" disabled />
    <TextInput source="name" validate={required()} />
    <NumberInput source="price" label="Default Price" validate={required()} />
    <DateInput source="available_since" validate={required()} />
  </RowForm>
);

In these examples, the same form component is used in createForm and editForm, but you can pass different forms (e.g. if some fields can be set at creation but not changed afterwards).

<EditableDatagrid>

<EditableDatagrid> renders like a regular <Datagrid>, adding some controls to create, edit, and delete records in place.

<EditableDatagrid> accepts the same props as <Datagrid>, plus 4 more props:

  • editForm (required): a component to display instead of a row when the users edits a record. It render as many columns as the <EditableDatagrid> has children
  • createForm: a component to display as the first row when the user creates a record
  • undoable: whether the edit and delete actions are undoable. Defaults to false.
  • noDelete: disable the inline Delete button

The <EditableDatagrid> component renders the editForm and createForm elements in a <table>, so these elements should render a <tr>. We advise you to use the <RowForm> component for editForm and createForm, which renders a <tr> by default. But you can also use your own component to render the row form (see below)

Tip: No need to include an <EditButton> as child, the <EditableDatagrid> component adds a column with edit/delete/save/cancel buttons itself.

Tip: To display a create button on top of the list, you should add the hasCreate prop to the <List> component, as in the example below.

Tip: To be able to add a new row when the list is empty, you need to bypass the default <List> empty page system by passing empty={false} as <List> prop.

import React from "react";
import {
  List,
  ListProps,
  TextField,
  DateField,
  SelectField,
} from "react-admin";
import { EditableDatagrid } from "@react-admin/ra-editable-datagrid";

import { ArtistForm } from "./ArtistForm";

const ArtistList = (props: ListProps) => (
  <List {...props} hasCreate empty={false}>
    <EditableDatagrid
      undoable
      createForm={<ArtistForm />}
      editForm={<ArtistForm />}
    >
      <TextField source="id" />
      <TextField source="firstname" />
      <TextField source="name" />
      <DateField source="dob" label="born" />
      <SelectField
        source="prof"
        label="Profession"
        choices={professionChoices}
      />
    </EditableDatagrid>
  </List>
);
import React from "react";
import { List, TextField, DateField, SelectField } from "react-admin";
import { EditableDatagrid } from "@react-admin/ra-editable-datagrid";

import { ArtistForm } from "./ArtistForm";

const ArtistList = (props) => (
  <List {...props} hasCreate empty={false}>
    <EditableDatagrid
      undoable
      createForm={<ArtistForm />}
      editForm={<ArtistForm />}
    >
      <TextField source="id" />
      <TextField source="firstname" />
      <TextField source="name" />
      <DateField source="dob" label="born" />
      <SelectField
        source="prof"
        label="Profession"
        choices={professionChoices}
      />
    </EditableDatagrid>
  </List>
);

Using Custom Actions

By default, the <EditableDatagrid> will show both edit and delete buttons when users hover a row. If you want to either customize the buttons behavior or provide more actions, you can leverage the actions prop, which accepts a React element. For instance, here's how to customize the delete button so that it asks users for a confirmation but still allows to undo the deletion:

import React from "react";
import { List, TextField } from "react-admin";
import {
  DeleteWithConfirmIconButton,
  EditableDatagrid,
  EditRowButton,
} from "@react-admin/ra-editable-datagrid";
import { ArtistForm } from "./ArtistForm";

const CustomAction = () => (
  <>
    <EditRowButton />
    <DeleteWithConfirmIconButton mutationMode="undoable" />
  </>
);

const ArtistList = (props: ListProps) => (
  <List
    {...props}
    hasCreate
    sort={{ field: "id", order: "DESC" }}
    empty={false}
  >
    <EditableDatagrid
      actions={<CustomAction />}
      // The mutation mode is still applied to updates
      mutationMode="undoable"
      editForm={<ArtistForm />}
    >
      <TextField source="id" />
      <TextField source="firstname" />
      <TextField source="name" />
    </EditableDatagrid>
  </List>
);
import React from "react";
import { List, TextField } from "react-admin";
import {
  DeleteWithConfirmIconButton,
  EditableDatagrid,
  EditRowButton,
} from "@react-admin/ra-editable-datagrid";
import { ArtistForm } from "./ArtistForm";

const CustomAction = () => (
  <>
    <EditRowButton />
    <DeleteWithConfirmIconButton mutationMode="undoable" />
  </>
);

const ArtistList = (props) => (
  <List
    {...props}
    hasCreate
    sort={{ field: "id", order: "DESC" }}
    empty={false}
  >
    <EditableDatagrid
      actions={<CustomAction />}
      // The mutation mode is still applied to updates
      mutationMode="undoable"
      editForm={<ArtistForm />}
    >
      <TextField source="id" />
      <TextField source="firstname" />
      <TextField source="name" />
    </EditableDatagrid>
  </List>
);

<RowForm>

<RowForm> renders a table row with one cell per child. That means that <RowForm> and <EditableDatagrid> should have the same number of children, and these children should concern the same source.

If you want to avoid the edition of a column, use a <Field> component instead of an <Input> component (like the <TextField> in the example above).

<RowForm> accepts the following props:

  • onSuccess: A function to execute after the row has been saved.
  • onFailure: A function to execute after the row has failed to be saved.
  • transform: A function to transform the row before it is saved.
  • undoable: Whether the edit and delete actions are undoable. Defaults to false.
  • submitOnEnter: Whether the form can be submitted by pressing the Enter key. Defaults to true.

Any additional props passed to <RowForm> are passed to the underlying react-final-form <Form> component. That means that you can pass e.g. initialValues, subscription, or validate props. Refer to the <Form> props documentation for more details.

import { RowForm, RowFormProps } from "@react-admin/ra-editable-datagrid";

const ArtistForm = (props) => (
  <RowForm initialValues={{ firstname: "John", name: "Doe" }} {...props}>
    <TextField source="id" disabled />
    <TextInput source="name" validate={required()} />
  </RowForm>
);
import { RowForm } from "@react-admin/ra-editable-datagrid";

const ArtistForm = (props) => (
  <RowForm initialValues={{ firstname: "John", name: "Doe" }} {...props}>
    <TextField source="id" disabled />
    <TextInput source="name" validate={required()} />
  </RowForm>
);

Recipes

Using a Custom Row Form

<RowForm> is just a component rendering a <Form> with a list of inputs in table cells. You can choose to use your own component in createForm and editForm. Here is a version of the previous editable datagrid without <RowForm>:

import React, { ReactElement } from "react";
import {
  List,
  ListProps,
  TextField,
  TextInput,
  DateField,
  DateInput,
  SelectField,
  SelectInput,
  required,
} from "react-admin";
import { Form } from "react-final-form";
import { TableRow, TableCell, Checkbox } from "@material-ui/core";
import {
  EditableDatagrid,
  SaveRowButton,
  CancelEditButton,
  RowFormProps,
} from "@react-admin/ra-editable-datagrid";

const ArtistForm = (props: RowFormProps) => {
  const {
    record,
    id,
    className,
    quitEditMode,
    selectable,
    basePath,
    resource,
    save,
    saving,
    selected,
    undoable,
    ...rest
  } = props;
  return (
    <Form
      initialValues={{ firstname: "John", name: "Doe", ...record }}
      onSubmit={save}
      {...rest}
    >
      {({ handleSubmit, invalid, dirty }): ReactElement => (
        <TableRow className={className} key={id}>
          <TableCell padding="checkbox">
            {selectable && (
              <Checkbox color="primary" checked={selected} disabled />
            )}
          </TableCell>
          <TableCell>
            <TextField
              source="id"
              record={record}
              resource={resource}
              basePath={basePath}
            />
          </TableCell>
          <TableCell>
            <TextInput
              source="firstname"
              validate={required()}
              record={record}
              resource={resource}
              basePath={basePath}
            />
          </TableCell>
          <TableCell>
            <TextInput
              source="name"
              validate={required()}
              record={record}
              resource={resource}
              basePath={basePath}
            />
          </TableCell>
          <TableCell>
            <DateInput
              source="dob"
              label="born"
              validate={required()}
              record={record}
              resource={resource}
              basePath={basePath}
            />
          </TableCell>
          <TableCell>
            <SelectInput
              source="prof"
              label="Profession"
              choices={professionChoices}
              record={record}
              resource={resource}
              basePath={basePath}
            />
          </TableCell>
          <TableCell>
            <SaveRowButton
              dirty={dirty}
              handleSubmit={handleSubmit}
              invalid={invalid}
              quitEditMode={quitEditMode}
              saving={saving}
              undoable={undoable}
            />
            <CancelEditButton cancel={quitEditMode} />
          </TableCell>
        </TableRow>
      )}
    </Form>
  );
};

const ArtistList = (props: ListProps) => (
  <List
    {...props}
    hasCreate
    sort={{ field: "id", order: "DESC" }}
    empty={false}
  >
    <EditableDatagrid
      undoable
      createForm={<ArtistForm />}
      editForm={<ArtistForm />}
      rowClick="edit"
    >
      <TextField source="id" />
      <TextField source="firstname" />
      <TextField source="name" />
      <DateField source="dob" label="born" />
      <SelectField
        source="prof"
        label="Profession"
        choices={professionChoices}
      />
    </EditableDatagrid>
  </List>
);
import React from "react";
import {
  List,
  TextField,
  TextInput,
  DateField,
  DateInput,
  SelectField,
  SelectInput,
  required,
} from "react-admin";
import { Form } from "react-final-form";
import { TableRow, TableCell, Checkbox } from "@material-ui/core";
import {
  EditableDatagrid,
  SaveRowButton,
  CancelEditButton,
} from "@react-admin/ra-editable-datagrid";

const ArtistForm = (props) => {
  const {
    record,
    id,
    className,
    quitEditMode,
    selectable,
    basePath,
    resource,
    save,
    saving,
    selected,
    undoable,
    ...rest
  } = props;
  return (
    <Form
      initialValues={{ firstname: "John", name: "Doe", ...record }}
      onSubmit={save}
      {...rest}
    >
      {({ handleSubmit, invalid, dirty }) => (
        <TableRow className={className} key={id}>
          <TableCell padding="checkbox">
            {selectable && (
              <Checkbox color="primary" checked={selected} disabled />
            )}
          </TableCell>
          <TableCell>
            <TextField
              source="id"
              record={record}
              resource={resource}
              basePath={basePath}
            />
          </TableCell>
          <TableCell>
            <TextInput
              source="firstname"
              validate={required()}
              record={record}
              resource={resource}
              basePath={basePath}
            />
          </TableCell>
          <TableCell>
            <TextInput
              source="name"
              validate={required()}
              record={record}
              resource={resource}
              basePath={basePath}
            />
          </TableCell>
          <TableCell>
            <DateInput
              source="dob"
              label="born"
              validate={required()}
              record={record}
              resource={resource}
              basePath={basePath}
            />
          </TableCell>
          <TableCell>
            <SelectInput
              source="prof"
              label="Profession"
              choices={professionChoices}
              record={record}
              resource={resource}
              basePath={basePath}
            />
          </TableCell>
          <TableCell>
            <SaveRowButton
              dirty={dirty}
              handleSubmit={handleSubmit}
              invalid={invalid}
              quitEditMode={quitEditMode}
              saving={saving}
              undoable={undoable}
            />
            <CancelEditButton cancel={quitEditMode} />
          </TableCell>
        </TableRow>
      )}
    </Form>
  );
};

const ArtistList = (props) => (
  <List
    {...props}
    hasCreate
    sort={{ field: "id", order: "DESC" }}
    empty={false}
  >
    <EditableDatagrid
      undoable
      createForm={<ArtistForm />}
      editForm={<ArtistForm />}
      rowClick="edit"
    >
      <TextField source="id" />
      <TextField source="firstname" />
      <TextField source="name" />
      <DateField source="dob" label="born" />
      <SelectField
        source="prof"
        label="Profession"
        choices={professionChoices}
      />
    </EditableDatagrid>
  </List>
);

Providing Custom Side Effects

Like other forms in react-admin, you can provide your own side effects in response to successful or failed actions by passing functions to the onSuccess or onFailure props:

import { TextInput, DateInput, SelectInput, useNotify } from "react-admin";
import {
  RowForm,
  RowFormProps,
  useCreateRowContext,
  useEditRowContext,
} from "@react-admin/ra-editable-datagrid";

const ArtistEditForm = (props: RowFormProps) => {
  const notify = useNotify();
  const { close } = useEditRowContext();

  const handleSuccess = (response) => {
    notify(
      `Artist ${response.data.name} ${response.data.firstName} has been updated`
    );
    close();
  };

  return (
    <RowForm onSuccess={handleSuccess} {...props}>
      <TextField source="id" />
      <TextInput source="firstname" validate={required()} />
      <TextInput source="name" validate={required()} />
      <DateInput source="dob" label="born" validate={required()} />
      <SelectInput
        source="prof"
        label="Profession"
        choices={professionChoices}
      />
    </RowForm>
  );
};

const ArtistCreateForm = (props: RowFormProps) => {
  const notify = useNotify();
  const { close } = useCreateRowContext();

  const handleSuccess = (response) => {
    notify(
      `Artist ${response.data.name} ${response.data.firstName} has been added`
    );
    close();
  };

  return (
    <RowForm onSuccess={handleSuccess} {...props}>
      <TextInput source="firstname" validate={required()} />
      <TextInput source="name" validate={required()} />
      <DateInput source="dob" label="born" validate={required()} />
      <SelectInput
        source="prof"
        label="Profession"
        choices={professionChoices}
      />
    </RowForm>
  );
};
import { TextInput, DateInput, SelectInput, useNotify } from "react-admin";
import {
  RowForm,
  useCreateRowContext,
  useEditRowContext,
} from "@react-admin/ra-editable-datagrid";

const ArtistEditForm = (props) => {
  const notify = useNotify();
  const { close } = useEditRowContext();

  const handleSuccess = (response) => {
    notify(
      `Artist ${response.data.name} ${response.data.firstName} has been updated`
    );
    close();
  };

  return (
    <RowForm onSuccess={handleSuccess} {...props}>
      <TextField source="id" />
      <TextInput source="firstname" validate={required()} />
      <TextInput source="name" validate={required()} />
      <DateInput source="dob" label="born" validate={required()} />
      <SelectInput
        source="prof"
        label="Profession"
        choices={professionChoices}
      />
    </RowForm>
  );
};

const ArtistCreateForm = (props) => {
  const notify = useNotify();
  const { close } = useCreateRowContext();

  const handleSuccess = (response) => {
    notify(
      `Artist ${response.data.name} ${response.data.firstName} has been added`
    );
    close();
  };

  return (
    <RowForm onSuccess={handleSuccess} {...props}>
      <TextInput source="firstname" validate={required()} />
      <TextInput source="name" validate={required()} />
      <DateInput source="dob" label="born" validate={required()} />
      <SelectInput
        source="prof"
        label="Profession"
        choices={professionChoices}
      />
    </RowForm>
  );
};

Note that we provide two additional side effects hooks: useEditRowContext and useCloseCreateRow which allows you to close the form.

Tip: If you use useNotify inside an onSuccess side effect for an Edit form in addition to the <EditableDatagrid undoable> prop, you will need to set the notification as undoable for the changes to take effects. Also, note that, on undoable forms, the onSuccess side effect will be called immediately, without any response argument.

const handleSuccess = () => {
  notify("Artist has been updated", undefined, undefined, true);
  close();
};
const handleSuccess = () => {
  notify("Artist has been updated", undefined, undefined, true);
  close();
};

Besides, the <RowForm> also accept a function for its transform prop allowing you to alter the data before sending it to the dataProvider:

import { TextInput, DateInput, SelectInput } from "react-admin";
import { RowForm, RowFormProps } from "@react-admin/ra-editable-datagrid";

const ArtistCreateForm = (props: RowFormProps) => {
  const handleTransform = (data) => {
    return {
      ...data,
      fullName: `${data.firstName} ${data.name}`,
    };
  };

  return (
    <RowForm transform={handleTransform} {...props}>
      <TextInput source="firstname" validate={required()} />
      <TextInput source="name" validate={required()} />
      <DateInput source="dob" label="born" validate={required()} />
      <SelectInput
        source="prof"
        label="Profession"
        choices={professionChoices}
      />
    </RowForm>
  );
};
import { TextInput, DateInput, SelectInput } from "react-admin";
import { RowForm } from "@react-admin/ra-editable-datagrid";

const ArtistCreateForm = (props) => {
  const handleTransform = (data) => {
    return {
      ...data,
      fullName: `${data.firstName} ${data.name}`,
    };
  };

  return (
    <RowForm transform={handleTransform} {...props}>
      <TextInput source="firstname" validate={required()} />
      <TextInput source="name" validate={required()} />
      <DateInput source="dob" label="born" validate={required()} />
      <SelectInput
        source="prof"
        label="Profession"
        choices={professionChoices}
      />
    </RowForm>
  );
};

CHANGELOG

v2.1.0

2021-09-06

  • (feat) allows to disable submit on enter with the submitOnEnter prop on RowForm

v2.0.1

2021-08-06

  • (fix) Correctly handle prop actions when set to false

v2.0.0

2021-08-04

  • (fix) Correctly handle prop actions when set to false

  • (fix) Breaking change: Renamed CreateResourceButton to CreateButton

  • (feat) Add support for the mutationMode prop introduced in react-admin@3.12.0.

    The undoable prop is deprecated, use mutationMode instead. It accepts the following values: pessimistic, optimistic, and undoable. See react-admin documentation about mutationMode.

  • (feat) Add support for custom actions on <EditableDatagrid> through the actions prop.

For instance, you could provide your own DeleteButton with confirmation and undoable notification:

import React from "react";
import { List, TextField } from "react-admin";
import {
  DeleteWithConfirmIconButton,
  EditableDatagrid,
  EditRowButton,
} from "@react-admin/ra-editable-datagrid";
import { ArtistForm } from "./ArtistForm";

const CustomAction = () => (
  <>
    <EditRowButton />
    <DeleteWithConfirmIconButton mutationMode="undoable" />
  </>
);

const ArtistList = (props: ListProps) => (
  <List
    {...props}
    hasCreate
    sort={{ field: "id", order: "DESC" }}
    empty={false}
  >
    <EditableDatagrid
      actions={<CustomAction />}
      // The mutation mode is still applied to updates
      mutationMode="undoable"
      editForm={<ArtistForm />}
    >
      <TextField source="id" />
      <TextField source="firstname" />
      <TextField source="name" />
    </EditableDatagrid>
  </List>
);
import React from "react";
import { List, TextField } from "react-admin";
import {
  DeleteWithConfirmIconButton,
  EditableDatagrid,
  EditRowButton,
} from "@react-admin/ra-editable-datagrid";
import { ArtistForm } from "./ArtistForm";

const CustomAction = () => (
  <>
    <EditRowButton />
    <DeleteWithConfirmIconButton mutationMode="undoable" />
  </>
);

const ArtistList = (props) => (
  <List
    {...props}
    hasCreate
    sort={{ field: "id", order: "DESC" }}
    empty={false}
  >
    <EditableDatagrid
      actions={<CustomAction />}
      // The mutation mode is still applied to updates
      mutationMode="undoable"
      editForm={<ArtistForm />}
    >
      <TextField source="id" />
      <TextField source="firstname" />
      <TextField source="name" />
    </EditableDatagrid>
  </List>
);

v1.3.5

2021-07-28

  • (fix) Ensure submitting on enter does not discard validation errors

v1.3.4

2021-07-27

  • (fix) Update Delete Icon buttons to use ra-core hooks

v1.3.3

2021-07-19

  • (fix) Fix creating a record fails when the Datagrid is empty

v1.3.2

2021-07-16

  • (fix) Fix Edit button does not respond to click

v1.3.1

2021-06-29

  • (fix) Update peer dependencies ranges (support react 17)

v1.3.0

2021-06-14

  • (feat) Add support for side effects on <RowForm>.

You can now provide your own side effects in response to successful/failed update/creation in an <EditableDatagrid> by passing functions to the onSuccess or onFailure props:

import {
  DateInput,
  SelectInput,
  TextField,
  TextInput,
  useNotify,
} from "react-admin";
import {
  RowForm,
  RowFormProps,
  useEditRowContext,
  useCreateRowContext,
} from "@react-admin/ra-editable-datagrid";

const ArtistEditForm = (props: RowFormProps) => {
  const notify = useNotify();
  const { close } = useEditRowContext();

  const handleSuccess = (response) => {
    notify(
      `Artist ${response.data.name} ${response.data.firstName} has been updated`
    );
    close();
  };

  return (
    <RowForm onSuccess={handleSuccess} {...props}>
      <TextField source="id" />
      <TextInput source="firstname" validate={required()} />
      <TextInput source="name" validate={required()} />
      <DateInput source="dob" label="born" validate={required()} />
      <SelectInput
        source="prof"
        label="Profession"
        choices={professionChoices}
      />
    </RowForm>
  );
};

const ArtistCreateForm = (props) => {
  const notify = useNotify();
  const { close } = useCreateRowContext();

  const handleSuccess = (response) => {
    notify(
      `Artist ${response.data.name} ${response.data.firstName} has been added`
    );
    close();
  };

  return (
    <RowForm onSuccess={handleSuccess} {...props}>
      <TextInput source="firstname" validate={required()} />
      <TextInput source="name" validate={required()} />
      <DateInput source="dob" label="born" validate={required()} />
      <SelectInput
        source="prof"
        label="Profession"
        choices={professionChoices}
      />
    </RowForm>
  );
};
import {
  DateInput,
  SelectInput,
  TextField,
  TextInput,
  useNotify,
} from "react-admin";
import {
  RowForm,
  useEditRowContext,
  useCreateRowContext,
} from "@react-admin/ra-editable-datagrid";

const ArtistEditForm = (props) => {
  const notify = useNotify();
  const { close } = useEditRowContext();

  const handleSuccess = (response) => {
    notify(
      `Artist ${response.data.name} ${response.data.firstName} has been updated`
    );
    close();
  };

  return (
    <RowForm onSuccess={handleSuccess} {...props}>
      <TextField source="id" />
      <TextInput source="firstname" validate={required()} />
      <TextInput source="name" validate={required()} />
      <DateInput source="dob" label="born" validate={required()} />
      <SelectInput
        source="prof"
        label="Profession"
        choices={professionChoices}
      />
    </RowForm>
  );
};

const ArtistCreateForm = (props) => {
  const notify = useNotify();
  const { close } = useCreateRowContext();

  const handleSuccess = (response) => {
    notify(
      `Artist ${response.data.name} ${response.data.firstName} has been added`
    );
    close();
  };

  return (
    <RowForm onSuccess={handleSuccess} {...props}>
      <TextInput source="firstname" validate={required()} />
      <TextInput source="name" validate={required()} />
      <DateInput source="dob" label="born" validate={required()} />
      <SelectInput
        source="prof"
        label="Profession"
        choices={professionChoices}
      />
    </RowForm>
  );
};

Note that we provide two additional side effects hooks: useEditRowContext and useCloseCreateRow, which allow you to close the form.

Besides, the <RowForm> also accepts a function for its transform prop, allowing you to alter the data before sending it to the dataProvider:

const ArtistCreateForm = (props) => {
  const handleTransform = (data) => {
    return {
      ...data,
      fullName: `${data.firstName} ${data.name}`,
    };
  };

  return (
    <RowForm transform={handleTransform} {...props}>
      <TextInput source="firstname" validate={required()} />
      <TextInput source="name" validate={required()} />
      <DateInput source="dob" label="born" validate={required()} />
      <SelectInput
        source="prof"
        label="Profession"
        choices={professionChoices}
      />
    </RowForm>
  );
};
const ArtistCreateForm = (props) => {
  const handleTransform = (data) => {
    return {
      ...data,
      fullName: `${data.firstName} ${data.name}`,
    };
  };

  return (
    <RowForm transform={handleTransform} {...props}>
      <TextInput source="firstname" validate={required()} />
      <TextInput source="name" validate={required()} />
      <DateInput source="dob" label="born" validate={required()} />
      <SelectInput
        source="prof"
        label="Profession"
        choices={professionChoices}
      />
    </RowForm>
  );
};

v1.2.0

2021-05-17

  • (chore) Upgrade to react-admin 3.15
  • (feat) Ensure all components with custom styles are overridable through MUI theme by providing their key (RaEditableDatagrid, RaEditableDatagridRow and RaRowForm).

v1.1.2

2021-05-11

  • Fix <EditableDatagrid> fails when wrapped

v1.1.1

2020-11-03

  • Add the noDelete prop to <EditableDatagrid> to disable the inline Delete button

v1.1.0

2020-10-05

  • Upgrade to react-admin 3.9

v1.0.4

2020-09-30

  • Update Readme

v1.0.3

2020-09-17

  • (fix) Fix crash on row deletion and impossible row creation

v1.0.2

2020-09-16

  • (deps) Upgrade dependencies

v1.0.1

2020-09-07

  • (feat) Add support for expand

v1.0.0

2020-08-05

  • First release