• 关于antdpro的EdittableProTable编辑时两个下拉搜索框的数据联动以及数据回显(以及踩坑)


    需求:使用antdpro的editprotable编辑两个下拉框,且下拉框是一个搜索下拉框。下拉框1和2的值是一个编码和名字的联动关系,1变化会带动2,2变化会带动1的一个联动作用。(最后有略完整的代码,但是因为公司项目问题,删掉了一些不必要的代码,不确保运行成功)

    在这里插入图片描述

    我使用的是renderFormItem进行渲染Select,并绑定了form

    修改对应的下拉框数据不难,但是数据回显比较难,我网上看了好多,很多是说绑定form,用form.setfieldValue,但是我一直失败显示不出来,网上也没搜到我这个回显的方法,官方文档也写得很少。

    最后是试出来的方式。

    1、使用antdpro的EdittableProTable

    <EditableProTable<AdminAccountItem>
                columns={columns}
                actionRef={actionRef}
                cardBordered
                form={tableForm}
                request={async (params = {}, sort, filter) => {
                    console.log(sort, filter);
                    // await waitTime(2000);
                    setExParam(params as unknown as AdminAccountItem);
                    return request<{
                        data: AdminAccountItem[];
                    }>('/getList', {
                        params,
                    }).then(res => {
                        setListData(res.data)
                        return res
                    });
                }}
                editable={{
                    form: tableForm,
                    editableKeys,
                    // type: 'multiple',
                    onSave: async (rowKey, data, row) => {
                        // console.log('============', tableForm.getFieldsValue[editableKeys[0]]());
                        console.log('row', data);
                        await adminApi.updateAdmin(data)
                      },
                    onCancel:async () => {
                        
                    },
                    onChange: setEditableRowKeys,
                    // 设置编辑只留保存和取消按钮
                    actionRender: (row, config, dom) => [dom.save, dom.cancel],
                  }}
                value={listData}
                onChange={setListData}
                columnsState={{
                    persistenceKey: 'pro-table-singe-demos',
                    persistenceType: 'localStorage',
                    onChange(value) {
                        console.log('value: ', value);
                    },
                }}
                rowKey="id"
                search={{
                    labelWidth: 'auto',
                }}
                options={{
                    setting: {
                        listsHeight: 400,
                    },
                }}
    
                form={{
                    // 由于配置了 transform,提交的参与与定义的不同这里需要转化一下
                    syncToUrl: (values, type) => {
                        if (type === 'get') {
                            return {
                                ...values,
                                created_at: [values.startTime, values.endTime],
                            };
                        }
                        return values;
                    },
                }}
                pagination={{
                    pageSize: 10,
                    onChange: (page) => console.log(page),
                }}
                // toolbar={{
                //     actions: []
                // }}
                dateFormatter="string"
                headerTitle="管理员列表"
            >
            </EditableProTable>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    这里面比较重要的参数一个就是
    这两个决定了在表格中点击编辑修改然后保存之后,数据会不会回显到表格中(我前面看了很多教程把onchange注释掉了所以修改后一直回显不出来,走了蛮多弯路)

    value={listData}
    onChange={setListData}
    
    • 1
    • 2

    还有一个就是edittable了,里面最重要的就是
    form:tableForm

    const [tableForm] = Form.useForm<AdminAccountItem>();
    
    • 1

    form在数据联动起很重要的作用,但是也因为它的用法,普通表单容易修改,但是用在列表中,找不到用法,走了很多弯路。

    还有一个就是编辑行的key值,也是你table设置的key值,editableKeys,其他可以看看官网

    const [editableKeys, setEditableRowKeys] = useState<React.Key[]>([])
    
    • 1

    这个在后面数据联动和tableForm一起使用起到重要作用。

    editable={{
                    form: tableForm,
                    editableKeys,
                    // type: 'multiple',
                    onSave: async (rowKey, data, row) => {
                        // console.log('============', tableForm.getFieldsValue[editableKeys[0]]());
                        console.log('row', data);
                        await adminApi.updateAdmin(data)
                      },
                    onCancel:async () => {
                        
                    },
                    onChange: setEditableRowKeys,
                    // 设置编辑只留保存和取消按钮
                    actionRender: (row, config, dom) => [dom.save, dom.cancel],
                  }}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2、表格column的设置

    我这里需要修改的是组织id和组织名称
    设置两个onSelect选中时获取远程数据

    {
                title: '组织ID',
                dataIndex: 'orgId',
                copyable: true,
                ellipsis: true,
                hideInSearch: true,
                valueType: 'select',
                renderFormItem: (_, data, form) => {
                    return (
                            <Select
                                options={orgOptions}
                                showSearch={true}
                                onSelect={onOrgIdSelect}
                                onSearch={(value) => getList('orgId', value)}
                                >
                            </Select>
                    )
                },
                render: (_, data) => {
                    return <div>{data.orgId}</div>
                }
            },
            {
                title: '组织名称',
                dataIndex: 'namePath',
                copyable: true,
                ellipsis: true,
                hideInSearch: true,
                valueType: 'select',
                renderFormItem: (_, data, from) => {
    
                    return (
                            <Select                        
                                options={orgNameOptions}
                                showSearch={true}
                                onSelect={onOrgNameSelect}
                                onSearch={(value) => getList('orgName', value)}
                                >
                            </Select>
                    )
                },
                render: (_, data) => {
                    return <div>{data.namePath}</div>
                }
            },
            {
                title: '操作',
                valueType: 'option',
                key: 'option',
                render: (text, record, _, action) => [
                    <a
                        key="editable"
                        onClick={() => {
                        action?.startEditable?.(record.id);
                        setOrgOptions([])
                        setOrgNameOptions([])
                        }}
                    >
                        编辑
                    </a>
                ],
            },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    3、用到的方法

    这里是两个onSelect以及获取下拉框数据,来自同一个接口
    但为了区分数据回显的两个下拉框,因为一个是id一个是name的显示,所以我设置的两个Select的options数据value和label都分别是相同的,所以获取数据分了id和name的区别(还有个原因是我用官网的下拉搜索框的组件一直有点问题)

     // 获取下拉框数据
        const getList = debounce(((selectName: string, param: string| undefined)=> {
            // 组织名称筛选时-正则匹配获取参数最后的组织id
            var regex1 = /(?<=\()(.+?)(?=\))/g;; 
            if(param?.match(regex1) !== null ) {
               let res: string| undefined = param?.match(regex1)?.[0] 
               param = res
            }
            // 下拉框是组织id
            if(selectName == 'orgId') {
              return adminApi.getDept({searchDept: param}).then((response: any) => {
                // 当组织名称被选中,数据则只有一条
                if(response.data.length == 1) {
                    console.log(tableForm.getFieldsValue());
                    // 设置组织id名称变化
                    tableForm.setFieldsValue({
                        [editableKeys[0] as number] : {
                            'orgId': response.data[0].value
                        }
                        
                    })
                  }
                  response.data?.map((item: selectValueType) => {
                    item.label = item.value
                  })
                  setOrgOptions(response.data)
                  
                })
              }
              // 下拉框是组织名称
              if(selectName == 'orgName') {
                return adminApi.getDept({searchDept:param}).then((response: any) => {
                    // 设置
                    if(response.data.length == 1) {
                        tableForm.setFieldsValue({
                            [editableKeys[0] as number] : {
                                'namePath': response.data[0].label
                            }
                            
                        })
                      }
                    response.data?.map((item: selectValueType) => {
                        item.value = item.label;
                      })
                    setOrgNameOptions(response.data)
                  })
                }
        }), 800)
    
        const onOrgIdSelect = async (selected: string) => {
            await getList('orgName', selected)
        }
        const onOrgNameSelect = async (selected: string) => {
            await getList('orgId', selected)
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    踩到的坑

    其中数据回显的使用,注意tableForm.setFieldsValue的使用
    我之前就是一直在这里踩坑,一直回显不出来,后面打印了
    tableForm.getFieldsValue()才知道,这个tableForm里面,因为外层是table包裹的form,而且编辑的是行,所以外层包裹了一层key值,我这里因为设置table的key值是id是个数字,所以是这样设置才生效了。

    tableForm.setFieldsValue({
                        [editableKeys[0] as number] : {
                            'orgId': response.data[0].value
                        }
                        
                    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    还有一些数据回显设置
    比如 if(response.data.length == 1)
    这里是因为是下拉搜索框,所以在我选择某一下拉框后,根据选中的value搜索另一个下拉框的值,因为二者是一一对应的关系,所以对应另一个下拉框也应该只有一个,所以直接设置另一个下拉框是第一个值

    4、完整代码

    import {DownloadOutlined, EllipsisOutlined, PlusOutlined} from '@ant-design/icons';
    import type {ActionType, ProColumns} from '@ant-design/pro-components';
    import {
        ModalForm,
        ProForm,
        ProFormDateRangePicker,
        ProFormSelect,
        ProFormText,
    } from '@ant-design/pro-components';
    import {ProTable, EditableProTable,TableDropdown,} from '@ant-design/pro-components';
    import {Button, Dropdown, Space, Tag, Form, message, Select, Divider, Popconfirm, Input} from 'antd';
    import React, {SetStateAction, useEffect, useRef, useState} from 'react';
    import request from 'umi-request';
    import adminApi from "@/services/admin"; 
    import {DefaultOptionType} from 'antd/es/select';
    import {ProFormItem, ProFormItemProps} from "@ant-design/pro-form";
    import {useModel} from "@@/exports";
    
    import debounce from 'lodash/debounce';
    export const waitTimePromise = async (time: number = 100) => {
        return new Promise((resolve) => {
            setTimeout(() => {
                resolve(true);
            }, time);
        });
    };
    
    export const waitTime = async (time: number = 100) => {
        await waitTimePromise(time);
    };
    
    type AdminAccountItem = {
        url: string;
        username: string;
        staffName: string;
        roleName: string;
        orgId: string;
        namePath: string;
        id: number;
        number: number;
        title: string;
        labels: {
            name: string;
            color: string;
        }[];
        state: string;
        comments: number;
        created_at: string;
        updated_at: string;
        closed_at?: string;
    };
    
    type saveAdminDataType = {
        roleId: string;
        staffId: string;
        orgId: string;
    }
    
    interface selectValueType {
        label: string;
        value: string;
    }
    
    export default () => {
    
        const [tableForm] = Form.useForm<AdminAccountItem>();
    
    
    
        const [listData, setListData] = useState<readonly AdminAccountItem[]>()
        const [exportParam, setExParam] = useState<AdminAccountItem>();
    
        // 组织id下拉框数据
        const [orgOptions, setOrgOptions] = useState<selectValueType[]>([]);
        // 组织名称下拉框数据
        const [orgNameOptions, setOrgNameOptions] = useState<selectValueType[]>([]);
        
     const [editableKeys, setEditableRowKeys] = useState<React.Key[]>([])
        // 获取下拉框数据
        const getList = debounce(((selectName: string, param: string| undefined)=> {
            // 组织名称筛选时-正则匹配获取参数最后的组织id
            var regex1 = /(?<=\()(.+?)(?=\))/g;; 
            if(param?.match(regex1) !== null ) {
               let res: string| undefined = param?.match(regex1)?.[0] 
               param = res
            }
            // 下拉框是组织id
            if(selectName == 'orgId') {
              return adminApi.getDept({searchDept: param}).then((response: any) => {
                // 当组织名称被选中,数据则只有一条
                if(response.data.length == 1) {
                    console.log(tableForm.getFieldsValue());
                    // 设置组织id名称变化
                    tableForm.setFieldsValue({
                        [editableKeys[0] as number] : {
                            'orgId': response.data[0].value
                        }
                        
                    })
                  }
                  response.data?.map((item: selectValueType) => {
                    item.label = item.value
                  })
                  setOrgOptions(response.data)
                  
                })
              }
              // 下拉框是组织名称
              if(selectName == 'orgName') {
                return adminApi.getDept({searchDept:param}).then((response: any) => {
                    // 设置
                    if(response.data.length == 1) {
                        tableForm.setFieldsValue({
                            [editableKeys[0] as number] : {
                                'namePath': response.data[0].label
                            }
                            
                        })
                      }
                    response.data?.map((item: selectValueType) => {
                        item.value = item.label;
                      })
                    setOrgNameOptions(response.data)
                  })
                }
        }), 800)
    
        const onOrgIdSelect = async (selected: string) => {
            await getList('orgName', selected)
        }
        const onOrgNameSelect = async (selected: string) => {
            await getList('orgId', selected)
        }
        const columns: ProColumns<AdminAccountItem>[] = [
            {
                title: '组织ID',
                dataIndex: 'orgId',
                copyable: true,
                ellipsis: true,
                hideInSearch: true,
                valueType: 'select',
                renderFormItem: (_, data, form) => {
                    return (
                            <Select
                                options={orgOptions}
                                showSearch={true}
                                onSelect={onOrgIdSelect}
                                onSearch={(value) => getList('orgId', value)}
                                >
                            </Select>
                    )
                },
                render: (_, data) => {
                    return <div>{data.orgId}</div>
                }
            },
            {
                title: '组织名称',
                dataIndex: 'namePath',
                copyable: true,
                ellipsis: true,
                hideInSearch: true,
                valueType: 'select',
                renderFormItem: (_, data, from) => {
    
                    return (
                            <Select                        
                                options={orgNameOptions}
                                showSearch={true}
                                onSelect={onOrgNameSelect}
                                onSearch={(value) => getList('orgName', value)}
                                >
                            </Select>
                    )
                },
                render: (_, data) => {
                    return <div>{data.namePath}</div>
                }
            },
            {
                title: '操作',
                valueType: 'option',
                key: 'option',
                render: (text, record, _, action) => [
                    <a
                        key="editable"
                        onClick={() => {
                        action?.startEditable?.(record.id);
                        setOrgOptions([])
                        setOrgNameOptions([])
                        }}
                    >
                        编辑
                    </a>
                ],
            },
        ];
        
        
       
    
        return (
    
            <EditableProTable<AdminAccountItem>
                columns={columns}
                actionRef={actionRef}
                cardBordered
                form={tableForm}
                request={async (params = {}, sort, filter) => {
                    console.log(sort, filter);
                    // await waitTime(2000);
                    setExParam(params as unknown as AdminAccountItem);
                    return request<{
                        data: AdminAccountItem[];
                    }>('getAdminAccount', {
                        params,
                    }).then(res => {
                        setListData(res.data)
                        return res
                    });
                }}
    
                editable={{
                    form: tableForm,
                    editableKeys,
                    // type: 'multiple',
                    onSave: async (rowKey, data, row) => {
                        console.log('row', data);
                        await adminApi.updateAdmin(data)
                      },
                    onCancel:async () => {
                        
                    },
                    onChange: setEditableRowKeys,
                    // 设置编辑只留保存和取消按钮
                    actionRender: (row, config, dom) => [dom.save, dom.cancel],
                  }}
                value={listData}
                onChange={setListData}
                columnsState={{
                    persistenceKey: 'pro-table-singe-demos',
                    persistenceType: 'localStorage',
                    onChange(value) {
                        console.log('value: ', value);
                    },
                }}
                rowKey="id"
                search={{
                    labelWidth: 'auto',
                }}
                options={{
                    setting: {
                        listsHeight: 400,
                    },
                }}
    
                form={{
                    // 由于配置了 transform,提交的参与与定义的不同这里需要转化一下
                    syncToUrl: (values, type) => {
                        if (type === 'get') {
                            return {
                                ...values,
                                created_at: [values.startTime, values.endTime],
                            };
                        }
                        return values;
                    },
                }}
                pagination={{
                    pageSize: 10,
                    onChange: (page) => console.log(page),
                }}
                dateFormatter="string"
                headerTitle="管理员列表"
            >
            </EditableProTable>
    
        );
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
  • 相关阅读:
    VPP以太网接口模式
    Nginx反向代理中文字符乱码
    白盒测试的各种方法
    Java指令重排序在多线程环境下的应对策略
    UE引擎实现ShadowMap、体积光(C++)
    Springboot信息泄露以及heapdump的利用
    Vue3+vite 使用import.meta.globEager代替require.context实现自动导入api
    牛客刷题系列之进阶版(组队竞赛,排序子序列,倒置字符串, 删除公共字符,修理牧场)
    设计模式 - 原型模式
    Matlab如何批量读取Excel数据?科研效率UpUp第3期
  • 原文地址:https://blog.csdn.net/qq_44179024/article/details/133918661