Skip to content

Instantly share code, notes, and snippets.

@Codennnn
Created October 15, 2021 04:02
Show Gist options
  • Save Codennnn/65025318584bc5ae79483b067888c672 to your computer and use it in GitHub Desktop.
Save Codennnn/65025318584bc5ae79483b067888c672 to your computer and use it in GitHub Desktop.
import type { FormInstance } from 'antd';
import { Button, Form, Input, Popconfirm, Table } from 'antd';
import React, { useContext, useEffect, useRef, useState } from 'react';
const EditableContext = React.createContext<FormInstance | null>(null);
const EditableRow = ({ index, ...props }: { index: number; [x: string]: any }) => {
const [form] = Form.useForm();
return (
<Form component={false} form={form}>
<EditableContext.Provider value={form}>
<tr {...props} />
</EditableContext.Provider>
</Form>
);
};
const EditableCell = ({
title,
editable,
children,
dataIndex,
record,
handleSave,
...restProps
}: any) => {
const form = useContext(EditableContext);
const inputRef = useRef<Input>(null);
const [editing, setEditing] = useState(false);
useEffect(() => {
if (editing) {
inputRef.current?.focus();
}
}, [editing]);
const toggleEdit = () => {
setEditing(!editing);
form?.setFieldsValue({
[dataIndex]: record[dataIndex],
});
};
const save = async () => {
try {
const values = await form?.validateFields();
toggleEdit();
handleSave({ ...record, ...values });
} catch (errInfo) {
console.log('Save failed:', errInfo);
}
};
let childNode = children;
if (editable) {
childNode = editing ? (
<Form.Item
name={dataIndex}
rules={[
{
required: true,
message: `${title} is required.`,
},
]}
style={{
margin: 0,
}}
>
<Input ref={inputRef} onBlur={save} onPressEnter={save} />
</Form.Item>
) : (
<div
className="editable-cell-value-wrap"
style={{
paddingRight: 24,
}}
onClick={toggleEdit}
>
{children}
</div>
);
}
return <td {...restProps}>{childNode}</td>;
};
export default function EditableTable() {
const [dataSource, setDataSource] = useState([
{
id: '123',
key: '0',
value: '32',
description: 'London, Park Lane no. 0',
require: true,
},
]);
const [count, setCount] = useState(2);
const handleDelete = (key) => {
setDataSource(dataSource.filter((item) => item.key !== key));
};
const handleAdd = () => {
const newData = {
id: `${count}`,
key: '0',
value: '32',
description: 'London, Park Lane no. 0',
require: true,
};
setDataSource([...dataSource, newData]);
setCount((preCount) => preCount + 1);
};
const handleSave = (row) => {
const newData = [...dataSource];
const index = newData.findIndex((item) => row.key === item.key);
const item = newData[index];
newData.splice(index, 1, { ...item, ...row });
setDataSource(newData);
};
const components = {
body: {
row: EditableRow,
cell: EditableCell,
},
};
const columns = [
{
title: 'KEY',
dataIndex: 'key',
},
{
title: 'VALUE',
dataIndex: 'value',
editable: true,
},
{
title: 'operation',
render(_, record) {
return dataSource.length >= 1 ? (
<Popconfirm title="Sure to delete?" onConfirm={() => handleDelete(record.key)}>
<button>Delete</button>
</Popconfirm>
) : null;
},
},
];
const col = columns.map((col) => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: (record) => ({
record,
editable: col.editable,
dataIndex: col.dataIndex,
title: col.title,
handleSave,
}),
};
});
return (
<div>
<Button type="primary" onClick={handleAdd}>
Add a row
</Button>
<Table
bordered
columns={col}
components={components}
dataSource={dataSource}
rowClassName={() => 'editable-row'}
/>
</div>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment