reactjscrudprimereact

How can I make newly added rows instantly editable?


I'm using prime react table to render dynamic data in react. I built my component with the help of the datatable docs.

When I click the add row button, I would like that the new added row to be instantly editable to the user (preferably with keyboard focus that I'll add later) without them using the edit button to edit the empty new row. Is that possible?

import { DataTable } from "primereact/datatable";
import { Column } from "primereact/column";
import { data } from "../data";
import { useState } from "react";
import { InputText } from "primereact/inputtext";

export const Table = () => {
  const [users, setUsers] = useState(data);

  const handleAddRow = (): void => {
    const newRow: any = {
      firstName: "",
      lastName: "",
      email: "",
      phone: "",
      freeTextField: "",
    };
    setUsers((prevList: any) => [newRow, ...prevList]);
  };

  const onRowEditComplete = (e: any) => {
    const _users = [...users];
    const { newData, index } = e;

    _users[index] = newData;

    setUsers(_users);
  };

  const textEditor = (options: any) => {
    return (
      <InputText
        type="text"
        value={options.value}
        onChange={(e) => options.editorCallback(e.target.value)}
      />
    );
  };

  return (
    <div className="table-wrapper">
      <h2 className="table-name">PrimeReact data table</h2>
      <button onClick={handleAddRow}>add row</button>

      <DataTable
        value={users}
        tableStyle={{ minWidth: "50rem" }}
        editMode="row"
        onRowEditComplete={onRowEditComplete}
      >
        <Column
          field="firstName"
          header="firstName"
          editor={(options) => textEditor(options)}
        ></Column>
        <Column
          field="lastName"
          header="lastName"
          editor={(options) => textEditor(options)}
        ></Column>
        <Column
          field="email"
          header="email"
          editor={(options) => textEditor(options)}
        ></Column>
        <Column
          field="phone"
          header="phone"
          editor={(options) => textEditor(options)}
        ></Column>
        <Column style={{ maxWidth: "15%" }} rowEditor>
          edit
        </Column>
      </DataTable>
    </div>
  );
};

Solution

  • This is possible with some tweaks on the above code.

    1. You need to introduce the prop dataKey on DataTable, this should be something unique to your data and something that you can add to the data on creation of the row, I used id for demo purpose.
    2. You need to introduce the prop onRowEditChange so that the table can handle the programmatic activation.
    3. You need to introduce the prop editingRows, which you will pass in a state that will indicate which row is in editing mode. This is handled internally by the table by utilising the dataKey prop mentioned in step 1.

    See the below code that will help to further understand the points above.

    * I have used some hardcoded values for the users state so that the code can work. Don't forget to change the value to your data

    export const Table = () => {
        const [users, setUsers] = useState([
            { id: 'john1', firstName: "John1", lastName: "Doe1", email: "john1@example.com", phone: "1234567890", freeTextField: "Random1" },
            { id: '2', firstName: "John2", lastName: "Doe2", email: "john2@example.com", phone: "2345678901", freeTextField: "Random2" },
            { id: '3', firstName: "John3", lastName: "Doe3", email: "john3@example.com", phone: "3456789012", freeTextField: "Random3" },
            { id: '4', firstName: "John4", lastName: "Doe4", email: "john4@example.com", phone: "4567890123", freeTextField: "Random4" },
            { id: '5', firstName: "John5", lastName: "Doe5", email: "john5@example.com", phone: "5678901234", freeTextField: "Random5" },
        ]);
        const [editingRows, setEditingRows] = useState({});
    
    
        const handleAddRow = (): void => {
            const newRow: any = {
                id: users.length + 1,
                firstName: "",
                lastName: "",
                email: "",
                phone: "",
                freeTextField: "",
            };
            setUsers((prevList: any) => [newRow, ...prevList]);
            const val = {...{ [`${users.length + 1}`]: true }  }
            setEditingRows(val);
        };
    
        const onRowEditComplete = (e: any) => {
            const _users = [...users];
            const { newData, index } = e;
    
            _users[index] = newData;
    
            setUsers(_users);
        };
    
        const textEditor = (options: any) => {
            return (
                <InputText
                    type="text"
                    value={options.value}
                    onChange={(e) => options.editorCallback(e.target.value)}
                />
            );
        };
    
        const onRowEditChange = (e:any) => {
            setEditingRows(e.data);
        }
    
        return (
            <div className="table-wrapper">
                <h2 className="table-name">PrimeReact data table</h2>
                <button onClick={handleAddRow}>add row</button>
    
                <DataTable
                    value={users}
                    tableStyle={{ minWidth: "50rem" }}
                    editMode="row"
                    editingRows={editingRows}
                    dataKey="id"
                    onRowEditChange={onRowEditChange}
                    onRowEditComplete={onRowEditComplete}
                >
                    <Column
                        field="firstName"
                        header="firstName"
                        editor={(options) => textEditor(options)}
                    ></Column>
                    <Column
                        field="lastName"
                        header="lastName"
                        editor={(options) => textEditor(options)}
                    ></Column>
                    <Column
                        field="email"
                        header="email"
                        editor={(options) => textEditor(options)}
                    ></Column>
                    <Column
                        field="phone"
                        header="phone"
                        editor={(options) => textEditor(options)}
                    ></Column>
                    <Column style={{ maxWidth: "15%" }} rowEditor>
                        edit
                    </Column>
                </DataTable>
            </div>
        );
    };