使用antd的Form组件动态创建复杂Select表单

2018-06-09  本文已影响0人  追风的云月
image.png
image.png

最近在项目中需要开发这样一个动态的select组件功能,梳理一下需求:

1.左侧的select和右侧的select是一个联动效果,右侧的select有几个option取决于选择了左侧的某个option
2.左侧的select有几个option取决于后台接口返回的数据
3.当页面加载时,会去接口中读取已有的变量和成员表单,一行的变量和成员可以看做一个整体
4.页面的表单可以用户手动增删

在开发过程的遇到的问题和解决方案记录:

1.动态增删表单

原理是使用getFieldValue方法和setFieldsValue方法,通过增加keys数组成员和删除keys数组成员来达到增删表单的效果。

removeFormItem = (k) => {
    const { form } = this.props;
    const keys = form.getFieldValue('keys');
    form.setFieldsValue({
        keys: keys.filter(key => key !== k),
    });
}

addFormItem = () => {
    const { form } = this.props;
    let keys = form.getFieldValue('keys');
    //增加表单时,这个key必须唯一,这里我引入uuid这个库来生成唯一ID 
    //( import UUID from 'uuid/v1')
    const nextKeys = keys.concat(UUID());
    form.setFieldsValue({
        keys: nextKeys,
    });
}
2.如何使用后台动态获取的值去设置页面的form表单

这个一度成为我的难点,通过后台返回的已有变量列表值去设置初始页面的表单数量,比如后台返回3个,我需要设置三个select,那么这一步在什么时候做。

const { getFieldDecorator, getFieldValue } = this.props.form;
let {taskVariableList,taskVariableOptionList}=this.props;
let formKeys=[],initValueObject={};
//使用已选列表每项的id作为已有表单的key值
if(taskVariableList.length>0){
    taskVariableList.map(variable=>{
        formKeys.push(variable.id);
        //将已有选项的值 以id-选项值的key-value形式存入一个对象
        initValueObject[variable.id]=variable
    })
}else{
    //如果没有已有列表 保证页面有一个初始的select
    if(this.state.haveNoVariable){
        formKeys.push(singleSelectUUID);
    }
}
getFieldDecorator('keys', { initialValue:formKeys});
3.如何渲染表单组件

一切的数据获取,数据增删都是储存在form的keys属性里面,那么const keys = form.getFieldValue('keys'),使用这个keys数组去渲染表单,因为每次增删改查都是操作这个keys数组,所以通过keys总是渲染正确实时的表单数据

<Form style={{margin:"0px 12px"}} className="task-variable">
    {
        keys&&keys.map((key,index)=>{
            return (
                <Row gutter={24} key={key}>
                    <Col span={11}>
                        <FormItem
                            {...formItemLayout}
                            label="变量"
                        >
                            {getFieldDecorator(`variable#${key}`,{initialValue:initValueObject[key]?initValueObject[key]["fromDimensionId"]:initialLeftValue,})(
                                <Select onChange={this.handleNewVariableChange.bind(this,taskVariableOptionList,key)}>
                                    {taskVariableOptionList.map(dimension=>{
                                        return (
                                            <Option value={dimension.fromDimensionId} key={`${dimension.id}-${index}`}>{dimension.name}</Option>
                                        )
                                    })}
                                </Select>
                            )}
                        </FormItem>
                    </Col>
                    <Col span={11}>
                        <FormItem
                            {...formItemLayout}
                            label="成员"
                        >
                            {this.renderSubItem(initValueObject,taskVariableOptionList,key,getFieldDecorator,initValueObject[key]?initValueObject[key]["fromCodeId"]:initialRightValue)}
                        </FormItem>
                    </Col>
                    <Col className="select-action-wrap" span={2}>
                        {keys.length ===(index+1)&&keys.length!==1? (
                            <i className="icon font_family" onClick={this.addFormItem}>&#xe644;</i>
                        ) : <Icon
                            className="dynamic-delete-button"
                            type="minus-circle-o"
                            disabled={keys.length === 1}
                            onClick={() => this.removeFormItem(key)}
                        />}
                    </Col>
                </Row>
            )
        })
    }
</Form>
4.如何渲染根据左侧选择的option动态渲染右侧select组件

使用select的回调事件,每次选择左侧不同的option,将右侧的值存入state,然后读取这个值生成不同的option

handleNewVariableChange=(optionData,key,value)=>{
    /**
     * optionData 右边的option 数组
     * key 传入的form表单的key 也就是已有变量列表的id或者新增表单的id
     * value 左侧的option变化value值 是变量的fromDimensionId
     * */
    let fromCodeList=[];
    optionData.map(dimension=>{
        if(dimension.fromDimensionId===value){
            fromCodeList=dimension.fromCodeList
        }
    })
    //以key作为state的唯一标志 将属于该key的fromCodeList存入 之后右边的option只需要读这个对应的fromCodeList来生成option
    this.setState({
        [key]:{"fromCodeList":fromCodeList},
        optionChangeFlag:true
    })
}
renderSubItem = (initValueObject,taskVariableOptionList,key,getFieldDecorator,initSubValue) =>{
    /**
     * initValueObject 已有变量列表的id-value对应的对象
     * taskVariableOptionList 备选option列表
     * key 传入的form表单的key 也就是已有变量列表的id或者新增表单的id
     * getFieldDecorator form的方法
     * initSubValue 右侧option的默认值
     * */
    let items=[];
    if(!this.state[key]){
        //这一步判断左侧option没有变化过 也就是取默认的fromCodeList
        if(!initValueObject[key]){
            //这一步判断是新增的表单 所有右侧取taskVariableOptionList第一项的fromCodeList来生成option
            items=taskVariableOptionList.length>0&&taskVariableOptionList[0].fromCodeList||[];
        }else{
            //这一步判断是已有的表单列表 右侧要取对应的fromCodeList生成option
            let fromDimensionId=initValueObject[key].fromDimensionId;
            taskVariableOptionList.map(option=>{
                if(option.fromDimensionId===fromDimensionId){
                    items=option.fromCodeList
                }
            })
        }
    }else{
        //这一步判断如果左侧option变化了 是取左侧的option发生变化时存入的fromCodeList
        items=this.state[key].fromCodeList;
    }
    if(this.state.optionChangeFlag&&items.length>0){
        //如果左侧的option曾经发生变化 那么右侧的initvalue值取第一项的值
        initSubValue=items[0].id
    }
    if(items.length>0){
        return(
            <div>
                {getFieldDecorator(`member#${key}`,{initialValue:initSubValue})(
                    <Select >
                        {
                            items.map(suboption=>{
                                return (
                                    <Option value={suboption.id} key={suboption.id}>{suboption.name}</Option>
                                )
                            })
                        }
                    </Select>
                )}
            </div>
        )
    }else{
        return(
            <div>
                {getFieldDecorator(`member#${key}`,{initialValue:''})(
                    <Select initialValue={''}></Select>
                )}
            </div>
        )
    }
}
上一篇下一篇

猜你喜欢

热点阅读