Ant Design 可编辑行未将按钮从 "edit" 更改为 "save" 和 "cancel"

Antd Design EditableRow not changing buttons from "edit" to "save" and "cancel"

我正在使用 Antd 库,但我似乎无法找到我的错误所在。

这是我的 EditableTableCell 组件

import React, {Component} from 'react';
import { Form } from '@ant-design/compatible';
import '@ant-design/compatible/assets/index.css';
import { Input, InputNumber, Select, DatePicker } from "antd";
import moment from "moment";
import {EditableContext} from "./EditableTableRow";

const FormItem = Form.Item;
const Option = Select.Option;
class EditableTableCell extends Component {
    getInput = (record, dataIndex, title, getFieldDecorator) => {
        switch (this.props.inputType) {
            case "number":
                return (
                    <FormItem style={{ margin: 0 }}>
                        {getFieldDecorator(dataIndex, {
                            rules: [
                                {
                                    required: true,
                                    message: `Please Input ${title}!`
                                }
                            ],
                            initialValue: record[dataIndex]
                        })(
                            <InputNumber formatter={value => value} parser={value => value} />
                        )}
                    </FormItem>
                );
            case "date":
                return (
                    <FormItem style={{ margin: 0 }}>
                        {getFieldDecorator(dataIndex, {
                            initialValue: moment(record[dataIndex], this.dateFormat)
                        })(<DatePicker format={this.dateFormat} />)}
                    </FormItem>
                );
            case "select":
                return (
                    <FormItem style={{ margin: 0 }}>
                        {getFieldDecorator(dataIndex, {
                            initialValue: record[dataIndex]
                        })(
                            <Select style={{ width: 150 }}>
                                {[...Array(11).keys()]
                                    .filter(x => x > 0)
                                    .map(c => `Product ${c}`)
                                    .map((p, index) => (
                                        <Option value={p} key={index}>
                                            {p}
                                        </Option>
                                    ))}
                            </Select>
                        )}
                    </FormItem>
                );
            default:
                return (
                    <FormItem style={{ margin: 0 }}>
                        {getFieldDecorator(dataIndex, {
                            rules: [
                                {
                                    required: true,
                                    message: `Please Input ${title}!`
                                }
                            ],
                            initialValue: record[dataIndex]
                        })(<Input />)}
                    </FormItem>
                );
        }
    }
    render() {
        const { editing, dataIndex, title, inputType, record, index,...restProps} = this.props;
        return (
           <EditableContext.Consumer>
               {form => {
                   const { getFieldDecorator } = form;
                   return (
                       <td {...restProps}>
                           {editing ?
                               this.getInput(record, dataIndex, title, getFieldDecorator)
                               : restProps.children}
                       </td>
                   );
               }}
           </EditableContext.Consumer>
        );
    }
}

export default EditableTableCell;

这是我的 EditableTableCell 组件

import React, {Component} from 'react';
import { Form} from '@ant-design/compatible';

export const EditableContext = React.createContext();
class EditableTableRow extends Component {
    render() {
        return (
            <EditableContext.Provider value={this.props.form}>
                <tr {...this.props} />
            </EditableContext.Provider>
        );
    }
}

export default EditableTableRow=Form.create()(EditableTableRow);

我的 ProductsPage 组件存在错误

import React, {Component} from 'react';
import {Button, Layout, notification, Popconfirm, Space, Table,Typography} from "antd";
import {Link} from "react-router-dom";
import {Content} from "antd/es/layout/layout";
import EditableTableRow, {EditableContext} from "../components/EditableTableRow";
import EditableTableCell from "../components/EditableTableCell";
import API from "../server-apis/api";
import {employeesDataColumns} from "../tableColumnsData/employeesDataColumns";
import {CheckCircleFilled, InfoCircleFilled} from "@ant-design/icons";


class ProductsPage extends Component {
    constructor(props) {
        super(props);
        this.state = {
            data: [],
            error: null,
            isLoaded: false,
            editingKey: "",
            errorMessage: "",
         
        }
    }
    columns = [
        ...employeesDataColumns,
        {
            title: "Actions",
            dataIndex: "actions",
            width: "10%",
            render: (text, record) => {
                const editable = this.isEditing(record);
                return editable ? (
                    <span>
                                <EditableContext.Consumer>
                                  {form => (<a onClick={() => this.saveData(form, record.username)} style={{ marginRight: 8 }}>Save</a>)}
                                </EditableContext.Consumer>
                                <a onClick={this.cancel}>Cancel</a>
                            </span>
                ) : (
                    <Space size="middle">
                        <a onClick={() => this.edit(record.username)}>Edit</a>
                        <Popconfirm title="Are you sure you want to delete this product?"
                                    onConfirm={() => this.remove(record.username)}>
                            <a style={{color:"red"}}>Delete</a>
                        </Popconfirm>
                    </Space>
                );
            },
        }
    ];

    isEditing = (record) => {
        return record.username === this.state.editingKey;
    };

    edit(username) {
    
        this.setState({editingKey:username});
    }

    cancel = () => {
        this.setState({ editingKey: ""});
    };
    componentDidMount() {
        this.setState({ loading: true });
        const token="Bearer "+ JSON.parse(localStorage.getItem("token"));
        API.get(`users/all`,{ headers: { Authorization: token}})
            .then(res => {
                // console.log(res.data._embedded.productList);
                const employees = res.data._embedded.employeeInfoDtoList;
                this.setState({loading: false,data:employees });
            })
    }
    async remove(username) {
        const token="Bearer "+ JSON.parse(localStorage.getItem("token"));
        API.delete(`/users/${username}`,{ headers: { Authorization: token}})
            .then(() => {
                let updatedProducts = [...this.state.data].filter(i => i.username !== username);
                this.setState({data: updatedProducts});
                this.successfullyAdded("Employee is deleted. It wont have any access to the website anymore.")
            }).catch(()=>this.errorHappend("Failed to delete"));
    }

    hasWhiteSpace(s) {
        return /\s/g.test(s);
    }
    saveData(form,username) {
        form.validateFields((error, row) => {
            if (error) {
                return;
            }
            const newData = [...this.state.data];
            const index = newData.findIndex(item => username === item.username);
            const item = newData[index];
            newData.splice(index, 1, {
                ...item,
                ...row
            });
            const token="Bearer "+ JSON.parse(localStorage.getItem("token"));
            const response = API.put(`/users/${username}/update`, row,{ headers: { Authorization: token}})
                .then((response) => {
                    this.setState({ data: newData, editingKey: ""});
                    this.successfullyAdded("Empolyee info is updated")
                })
                .catch(error => {
                    this.setState({ errorMessage: error.message });
                    this.errorHappend("Failed to save changes.")
                    console.error('There was an error!', error);
                });
        });
    }
    successfullyAdded = (message) => {
        notification.info({
            message: `Notification`,
            description:message,
            placement:"bottomRight",
            icon: <CheckCircleFilled style={{ color: '#0AC035' }} />
        });
    };
    errorHappend = (error) => {
        notification.info({
            message: `Notification`,
            description:
                `There was an error! ${error}`,
            placement:"bottomRight",
            icon: <InfoCircleFilled style={{ color: '#f53333' }} />
        });
    };
    render() {
        const components = {
            body: {
                row: EditableTableRow,
                cell: EditableTableCell
            }
        };
        const columns = this.columns.map(col => {
            if (!col.editable) {
                return col;
            }
            return {
                ...col,
                onCell: record => {
                    const checkInput = index => {
                        switch (index) {
                            case "price":
                                return "number";
                            default:
                                return "text";
                        }
                    };
                    return {
                        record,
                        // inputType: col.dataIndex === "age" ? "number" : "text",
                        inputType: checkInput(col.dataIndex),
                        dataIndex: col.dataIndex,
                        title: col.title,
                        editing: this.isEditing(record)
                    };
                }
            };
        });
        const { data, loading } = this.state;
        return (
            <Layout>
                <div>
                    <Link to="/add-product">
                        <Button style={{float:"right", background: "#0AC035",marginBottom:"1em", marginTop:"1em" }}
                                type="primary">New emplyee</Button>
                    </Link>
                </div>
                <Content>
                
                    <Table components={components} bordered dataSource={data} columns={columns} loading={loading} rowKey={data.username} rowClassName="editable-row"/>
                </Content>
            </Layout>
        );
    }
}

export default ProductsPage;

这是我遇到的错误: enter image description here

而且我希望得到像 Antd 文档中所示的结果: enter image description here

如果你能帮我找出我错在哪里,我将不胜感激

更新的解决方案: 我发现了问题。在映射列的位置呈现,如果列不是可编辑列,则只需 return 列。您可以检查下面的代码。我添加了一个检查,如果它是 dataIndex === 'actions',那么 return 下面的代码: 请关注link: https://react-ts-v3fbst.stackblitz.io

变化:

1.In 列,我从操作对象中删除渲染函数:

{
      title: 'Actions',
      dataIndex: 'actions',
      width: '10%',
},

2。在映射列的渲染函数中,在此条件 if(!col.editable) { 之前添加以下代码:



if (col.dataIndex === 'actions') {
    return {
        ...col,
        render: (text, record) => {
            const editable = this.isEditing(record);
            return editable ? (
                <span>
                    <EditableContext.Consumer>
                        {(form) => (
                            <a onClick={() => this.saveData(form, record.username)} style={{ marginRight: 8 }}>
                                Save
                            </a>
                        )}
                    </EditableContext.Consumer>
                    <a onClick={this.cancel}>Cancel</a>
                </span>
            ) : (
                <Space size='middle'>
                    <a onClick={() => this.edit(record.username)}>Edit</a>
                    <Popconfirm title='Are you sure you want to delete this product?' onConfirm={() => this.remove(record.username)}>
                        <a style={{ color: 'red' }}>Delete</a>
                    </Popconfirm>
                </Space>
            );
        }
    };
}

当您点击编辑时,您将用户名设置为该特定行的键以进行编辑,确保每条记录中都有 username。我使用以下数据对此进行了测试:

const data = [
    { id: 8, name: 'baun', model: '2022', color: 'black', price: 358, quantity: 3, username: 'brvim' },
    { id: 3, name: 'galileo', model: '20221', color: 'white', price: 427, quantity: 7, username: 'john' }
];

最重要的是,您应该 select 该属性作为在所有记录中唯一的键。当您使用 username 时,我不知道您的业务逻辑或数据是什么样的,但从技术上讲,每条记录都可以具有相同的 username。因此,您必须 select 一些在您的完整数据中始终独一无二的东西。