antd頁面多表單校驗

Joydezhong發表於2019-04-10

問題

在做antd專案時發現,使用Form.create()(xxx)建立的模組裡面的Form表單提交前可以使用this.props.form.validateFieldsAndScroll()判斷是否校驗成功,this.props.form也就是整個頁面模組的Form,那麼,如果頁面上有多個Form,此時再使用this.props.form.validateFieldsAndScroll()判斷校驗結果就是對整個頁面的Form判斷,並不能夠對單個Form校驗結果做判斷,問題就在此,如何對單個Form做判斷?

解決方法

  1. 手動校驗,通過對錶單元素新增change事件監聽,獲取表單元素值,手動做校驗,這不失為一個方法,但有違react設計的思想。
  2. 把表單作為一個元件獨立出去,頁面通過props傳入表單元件需要的值,在表單元件內部單獨維護相關邏輯,這也是本文推薦的方式。

案例實現

Form子元件:

import React, { Component } from 'react';
import {Button, Form, Input, Select} from 'antd';

const FormItem = Form.Item;

class Forms extends Component{
  getItemsValue = ()=>{
      const val= this.props.form.getFieldsValue(); // 獲取from表單的值
      return val;
  }
  render(){
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 8 },
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 },
      },
    };
    const { form, initValue1, initValue2, initValueList } = this.props;
    const { getFieldDecorator } = form; // 校驗控制元件
    return(
      <Form style={{backgroundColor: '#fff', padding: '20px'}}>
        <FormItem
          {...formItemLayout}
          label={`相關數量`}
        >
          {getFieldDecorator(`amount`,{
            rules: [{
              message: '必填欄位!',
              required: true
            }],
            initialValue: initValue1 ? initValue1 : undefined
          })(
            <Input placeholder="請輸入"/>
          )}
        </FormItem>
        <FormItem
          {...formItemLayout}
          label={`選擇相關名稱`}
        >
          {getFieldDecorator(`name`,{
            rules: [{
              message: '必填欄位!',
              required: false
            }],
            initialValue: initValue2 ? initValue2 : undefined
          })(
            <Select
              placeholder="請選擇"
              onChange={this.handleSelectChange}
            >
              {
                initValueList && initValueList.map((x, i) => (
                  <Option value={x.Id} key={i}>{x.name}</Option>
                ))
              }
            </Select>
          )}
        </FormItem>
      </Form>
    )
  }
}

export default Form.create()(Forms);        //建立form例項
複製程式碼

Form子元件,接收父元件傳過來的初始資料,元件中getItemsValue自定義方法返回表單的值,需要在父元件中呼叫。

父元件:

import React, { Component } from 'react';
import { Modal, Button } from 'antd';
import Forms from './Forms'

export default class Modals extends Component {
    constructor(props) {
        super(props);
        this.state = {
          visible: false,
          initValue1: 0,
          initValue2: 'myName',
          initValueList: ["李雲龍", "李榮基", "李達"]
        };
    }
    handleClick = () => {
        this.setState({
            visible: true
        })
    };
    handleCreate = () => {
        let values = this.formRef.getItemsValue();
        // 獲取到子元件form的值,做進一步操作
        this.setState({
            visible: false
        })
    };
    render() {
        return (
            <section>
                <Modal
                  visible={this.state.visible}
                  title="編輯"
                  onOk={this.handleCreate}
                  onCancel={() => {
                    this.setState({ visible: false });
                  }}
                  okText="儲存"
                  cancelText="取消"
                >
                  <Forms
                    initValue1={initValue1}
                    initValue2={initValue2}
                    initValueList={initValueList}
                    wrappedComponentRef={(form) => this.formRef = form}
                  />
                </Modal>
                <Button onClick={()=>{ this.handleClick }}>點選彈框</Button>
            </section>
        );
    }
}
複製程式碼

這裡關鍵的是使用wrappedComponentRef屬性拿到這個Form的ref,簡單的理解為拿到子元件的form例項,因此,可以在handleCreate函式中通過this.formRef.getItemsValue()呼叫自子元件的方法獲取返回的form值。至此,上面的問題就解決了。

關於wrappedComponentRef的描述詳見antd官網描述

相關文章