Search code examples
reactjsantd

How to use Ant Design DatePicker inside Ant Design Editable Table?


I'm using Ant Design Editable Table where there is an operation column where there is an edit button. I have 2 other columns which are date and value. So what I want to have is when I press on the edit button for a specific row, I want to be able to change the date using <DatePicker /> component from Ant Design. I have not been able to find a solution anywhere online for me. What I have right now is:

EditableTable.js

import React, { useState } from "react";
import { Table, Form, Button, DatePicker } from "antd";

import EditableCell from "./EditableCell";

const OtherLocsTable = ({ data, setData }) => {
   const [form] = Form.useForm();
   const [editingKey, setEditingKey] = useState("");
   const isEditing = (record) => record.key === editingKey;
   const edit = (record) => {
      form.setFieldsValue({
         date: "",
         measurement: "",
         ...record,
      });
      setEditingKey(record.key);
   };
  const save = async (key) => {
    try {
      const row = await form.validateFields();
      const newData = [...data];
      const index = newData.findIndex((item) => key === item.key);

      if (index > -1) {
        const item = newData[index];
        newData.splice(index, 1, { ...item, ...row });
        setData(newData);
        setEditingKey("");
      } else {
        newData.push(row);
        setData(newData);
        setEditingKey("");
      }
    } catch (errInfo) {
      console.log("Validate Failed:", errInfo);
    }
  };
const columns = [
    {
      title: "Date",
      dataIndex: "date",
      key: "date",
      editable: true,
    },
    {
      title: "Measurement",
      dataIndex: "measurement",
      key: "measurement",
      editable: true,
    },
    {
      title: "Operation",
      dataIndex: "operation",
      render: (_, record) => {
        const editable = isEditing(record);
        const lastElement = [...data].pop();

        return editable ? (
          <span>
            <a
              href="javascript:;"
              onClick={() => save(record.key)}
              style={{
                marginRight: 8,
              }}
            >
              Save
            </a>
            <Popconfirm title="Sure to cancel?" onConfirm={cancel}>
              <a>Cancel</a>
            </Popconfirm>
          </span>
        ) : (
          <>
            <Typography.Link
              disabled={editingKey !== ""}
              onClick={() => edit(record)}
            >
              Edit
            </Typography.Link>
            {data.length > 1 ? (
              record.key === lastElement.key ? (
                <Typography.Link
                  type="danger"
                  disabled={editingKey !== ""}
                  onClick={() => deleteRow(record)}
                  style={{
                    marginLeft: 15,
                  }}
                >
                  Delete
                </Typography.Link>
              ) : null
            ) : null}
          </>
        );
      },
    },
  ];
const mergedColumns = columns.map((col) => {
    if (!col.editable) {
      return col;
    }

    return {
      ...col,
      onCell: (record) => ({
        record,
        inputType:
          col.dataIndex === loc
            ? "number"
            : col.dataIndex === "date"
            ? "date"
            : "text",
        dataIndex: col.dataIndex,
        title: col.title,
        editing: isEditing(record),
      }),
    };
  });
  return (
    <>
      <Popconfirm title="Confirm save changes?" onConfirm={handleSubmit}>
        <Button
          key="submit"
          style={{
            marginBottom: "1em",
            width: "100%",
            backgroundColor: "green",
          }}
        >
          Save Changes
        </Button>
      </Popconfirm>
      <Form form={form} component={false}>
        <Table
          components={{
            body: {
              cell: EditableCell,
            },
          }}
          bordered
          dataSource={data}
          columns={mergedColumns}
          rowClassName="editable-row"
          pagination={{
            onChange: cancel,
          }}
          rowKey="date"
        />
      </Form>
    </>
  );
};
}

EditableCell.j

import React from "react";
import { Form, Input, InputNumber, DatePicker } from "antd";
import moment from "moment";

const EditableCell = ({
  editing,
  dataIndex,
  title,
  inputType,
  record,
  index,
  children,
  ...restProps
}) => {
  const inputNode =
    inputType === "number" ? (
      <Form.Item
        style={{ margin: 0 }}
        name={dataIndex}
        rules={[
          {
            required: true,
            message: `Please Input ${title}!`,
          },
        ]}
      >
        <InputNumber formatter={(value) => value} parser={(value) => value} />
      </Form.Item>
    ) : inputType === "date" ? (
      <FormItem
        style={{ margin: 0 }}
        name={dataIndex}
        rules={[
          {
            required: true,
            message: `Please Input ${title}!`,
          },
        ]}
        initialValue={moment(record[dataIndex])}
      >
        <DatePicker />
      </FormItem>
    ) : (
      <Form.Item
        style={{ margin: 0 }}
        name={dataIndex}
        rules={[
          {
            required: true,
            message: `Please Input ${title}!`,
          },
        ]}
      >
        <Input />
      </Form.Item>
    );

  return <td {...restProps}>{editing ? inputNode : children}</td>;
};

export default EditableCell;

UPDATE Currently with the code I have, I'm getting an error where it says date.clone is not a function


Solution

  • I found a solution

    EditableTable.js

    import React, { useState } from "react";
    import { Table, Form, Button, DatePicker } from "antd";
    import moment from 'moment';
    
    import EditableCell from "./EditableCell";
    
    const OtherLocsTable = ({ data, setData }) => {
       const [form] = Form.useForm();
       const [editingKey, setEditingKey] = useState("");
       const isEditing = (record) => record.key === editingKey;
       const edit = (record) => {
          const {date, measurement} = record;
          form.setFieldsValue({
             date: (date) ? moment(date) : "",
             measurement: measurement || ""
          });
          setEditingKey(record.key);
       };
      const save = async (key) => {
        try {
          const row = await form.validateFields();
          const newData = [...data];
          const index = newData.findIndex((item) => key === item.key);
    
          if (index > -1) {
            const item = newData[index];
            newData.splice(index, 1, { ...item, ...row });
            setData(newData);
            setEditingKey("");
          } else {
            newData.push(row);
            setData(newData);
            setEditingKey("");
          }
        } catch (errInfo) {
          console.log("Validate Failed:", errInfo);
        }
      };
    const columns = [
        {
          title: "Date",
          dataIndex: "date",
          key: "date",
          editable: true,
        },
        {
          title: "Measurement",
          dataIndex: "measurement",
          key: "measurement",
          editable: true,
        },
        {
          title: "Operation",
          dataIndex: "operation",
          render: (_, record) => {
            const editable = isEditing(record);
            const lastElement = [...data].pop();
    
            return editable ? (
              <span>
                <a
                  href="javascript:;"
                  onClick={() => save(record.key)}
                  style={{
                    marginRight: 8,
                  }}
                >
                  Save
                </a>
                <Popconfirm title="Sure to cancel?" onConfirm={cancel}>
                  <a>Cancel</a>
                </Popconfirm>
              </span>
            ) : (
              <>
                <Typography.Link
                  disabled={editingKey !== ""}
                  onClick={() => edit(record)}
                >
                  Edit
                </Typography.Link>
                {data.length > 1 ? (
                  record.key === lastElement.key ? (
                    <Typography.Link
                      type="danger"
                      disabled={editingKey !== ""}
                      onClick={() => deleteRow(record)}
                      style={{
                        marginLeft: 15,
                      }}
                    >
                      Delete
                    </Typography.Link>
                  ) : null
                ) : null}
              </>
            );
          },
        },
      ];
    const mergedColumns = columns.map((col) => {
        if (!col.editable) {
          return col;
        }
    
        return {
          ...col,
          onCell: (record) => ({
            record,
            inputType:
              col.dataIndex === loc
                ? "number"
                : col.dataIndex === "date"
                ? "date"
                : "text",
            dataIndex: col.dataIndex,
            title: col.title,
            editing: isEditing(record),
          }),
        };
      });
      return (
        <>
          <Popconfirm title="Confirm save changes?" onConfirm={handleSubmit}>
            <Button
              key="submit"
              style={{
                marginBottom: "1em",
                width: "100%",
                backgroundColor: "green",
              }}
            >
              Save Changes
            </Button>
          </Popconfirm>
          <Form form={form} component={false}>
            <Table
              components={{
                body: {
                  cell: EditableCell,
                },
              }}
              bordered
              dataSource={data}
              columns={mergedColumns}
              rowClassName="editable-row"
              pagination={{
                onChange: cancel,
              }}
              rowKey="date"
            />
          </Form>
        </>
      );
    };
    }
    

    EditableCell.j

    import React from "react";
    import { Form, Input, InputNumber, DatePicker } from "antd";
    import moment from "moment";
    
    const EditableCell = ({
      editing,
      dataIndex,
      title,
      inputType,
      record,
      index,
      children,
      ...restProps
    }) => {
      const inputNode =
        inputType === "number" ? (
          <Form.Item
            style={{ margin: 0 }}
            name={dataIndex}
            rules={[
              {
                required: true,
                message: `Please Input ${title}!`,
              },
            ]}
          >
            <InputNumber formatter={(value) => value} parser={(value) => value} />
          </Form.Item>
        ) : inputType === "date" ? (
          <FormItem
            style={{ margin: 0 }}
            name={dataIndex}
            rules={[
              {
                required: true,
                message: `Please Input ${title}!`,
              },
            ]}
          >
            <DatePicker formate="DD-MM-YYYY" />
          </FormItem>
        ) : (
          <Form.Item
            style={{ margin: 0 }}
            name={dataIndex}
            rules={[
              {
                required: true,
                message: `Please Input ${title}!`,
              },
            ]}
          >
            <Input />
          </Form.Item>
        );
    
      return <td {...restProps}>{editing ? inputNode : children}</td>;
    };
    
    export default EditableCell;