DouyinFE / semi-design

🚀A modern, comprehensive, flexible design system and React UI library. 🎨 Provide more than 3000+ Design Tokens, easy to build your design system. Make Semi Design to Any Design. 🧑🏻‍💻 Design to Code in one click
https://semi.design
Other
8.43k stars 711 forks source link

Form partical validate triggers the validator of the non-specified field #510

Closed pointhalo closed 2 years ago

pointhalo commented 2 years ago

Which Component 出现bug的组件

semi-ui version

Expected result 期望的结果是什么

Actual result 实际的结果是什么

Steps to reproduce 复现步骤

Reproducible code 复现代码

class FormDemo extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            visible: false,
        }
        this.handleOk = this.handleOk.bind(this);
        this.getFormApi = this.getFormApi.bind(this);
    }

    handleOk() {
        this.formApi.validate(['active.title', 'active.LinkDetail'])
            .then((values) => {
                console.log(values)
            })
            .catch((errors) => {
                console.log(errors)
            });
    }

    getFormApi(formApi) {
        this.formApi = formApi;
    }

    render(){
        let message = '该项为必填项';
        return (
            <>

                    <Form
                        getFormApi={this.getFormApi}
                    >
                        <Button onClick={this.handleOk}>validate</Button>
                        <Button htmlType='reset'>reset</Button>
                                <Form.Select
                                    field='active.Title'
                                    placeholder='请选择'
                                    style={{width:'100%'}}
                                    rules={[
                                        { required: true, message },
                                    ]}
                                >
                                    <Option value="China">中国</Option>
                                    <Option value="US">美国</Option>
                                    <Option value="Europe">欧洲</Option>
                                    <Option value="Japan">日本</Option>
                                </Form.Select>
                                <Form.Input
                                    field='active.showLinkDetail'
                                    trigger='blur'
                                    rules={[
                                        { required: true, message },
                                    ]}
                                />

                                <Form.Select
                                    field='active.LinkDetail'
                                    style={{width:'100%'}}
                                    rules={[
                                        { required: true, message },
                                    ]}
                                >
                                    <Option value="China">中国</Option>
                                    <Option value="US">美国</Option>
                                    <Option value="Europe">欧洲</Option>
                                    <Option value="Japan">日本</Option>
                                </Form.Select>

                                <Form.Input
                                    field='department'
                                    trigger='blur'
                                    rules={[
                                        { required: true, message },
                                    ]}
                                />
                    </Form>
            </>
        );
    }
}

Additional information 补充说明

pointhalo commented 2 years ago

复现条件:validate[xxx] 数组中传入多级 fieldPath(例如 activity.needValidate),且这个fieldPath,前缀与其他 field 相同 (例如与 activity.a、activity.b的前缀都相同)。此时会导致 getNestedField判断错误,误以为 activity.a 、activity.b 是 activity.needValidate 的子级

https://github.com/DouyinFE/semi-design/blob/0e0b8cea0431ef4fa09de03ba48a8b2f0f0a67e9/packages/semi-foundation/form/foundation.ts#L272

    // All fields: a[0]、a[1]、b.type、b.name[2]、b.name[0]
    // input => output:
    //      a  => a[0]、a[1]
    //      b  => b.type、b.name[3]、b.name[2]
    _getNestedField(path: string): Map<string, FieldStaff> {
        const allRegisterField = this.fields;
        const allFieldPath = [...allRegisterField].map(item => item[0]);
        let nestedFieldPath = new Map();
        allFieldPath.forEach(item => {
            let itemPath = toPath(item);
            let targetPath = toPath(path);
            if (itemPath[0] === targetPath[0]) {
                const realField = allRegisterField.get(item);
                nestedFieldPath.set(item, realField);
            }
        });
        return nestedFieldPath;
    }