这篇文章主要整理了我在工作中,使用Form表单组件,进行数据校验的一些问题. 其中印象比较深刻的就是一个固定电话和客户账期的组合组件.(固定电话是由三个文本框组成,分别为区号,固号,以及分机号码.客户账期是由一个下拉选择框和文本框组合),开发过程中遇到的相关表单自定义校验问题和错误提示信息:
下图是页面展示效果:
之后项目上线,对之前的代码进行了优化修改.优化内容如下:
- 固定电话是否必填进行了可控制的校验,并且只显示一个提示信息.
- 客户账期下拉文本框组件,进行了修改.onChange的时候,清空了文本框框的值.
具体的展示效果是:
固定电话格式:区号和固话号码必填,(分机号非必填) 校验规则如下->
如果区号和固号都没填写,则提示:固号号码需必填
如果只填写了区号,或者只填写了固号,提交则提示:请输入完整的固话
只有当区号和固号都填写了,则验证通过!
验证通过的情况:
之前的应急处理方式是,Form.Item 做的嵌套,对每个字段进行单独的校验.(一个外层的Form.Item里面嵌套三个FormItem)
固定电话抽离做了个一个共用组件,客户基本信息是一个表单组件:
父组件:
<FormItem label="固定电话" required style={{ margin: 0 }}>
{getFieldDecorator("fixphoneNo", {
initialValue: {
areaNo: customerbasicInfo && customerbasicInfo.id ? customerbasicInfo.companyTelArea :'',
phoneNo:customerbasicInfo && customerbasicInfo.id ? customerbasicInfo.companyTel :'',
exNo: customerbasicInfo && customerbasicInfo.id ? customerbasicInfo.companyTelEx :'',
},
})(
<FixedphoneInput
form={form}
areafieldKey="companyTelArea"
phonefieldKey="companyTel"
exfiledKey="companyTelEx"
/>
)}
</FormItem>
固话文本框子组件:
import React from 'react';
import { Form, Input, Row, Col } from 'antd';
//固定电话文本框组合组件
class FixedPhoneInput extends React.Component {
static getDerivedStateFromProps(props) {
if ('value' in props) {
return {
...(props.value || {}),
};
}
return null;
}
constructor(props) {
super(props);
const value = props.value || {};
this.state = {
areaNo: value.areaNo || '', //区号
phoneNo: value.phoneNo || '', //固话号码
exNo: value.exNo || ''//分机号
};
}
checkFixedphone = (rule, value, callback) => {
const { form, areafieldKey, phonefieldKey, } = this.props;
const { setFields } = form;
const companyTelArea = form.getFieldValue('companyTelArea');
const companyTel = form.getFieldValue('companyTel');
if (!companyTelArea && !companyTel) {
callback('固话号码需必填');
setFields({
[phonefieldKey]: { value:companyTel,errors: null },
});
} else if (companyTelArea && !companyTel) {
callback('请输入完整的固话');
setFields({
[phonefieldKey]: {value:companyTel, errors: '' },
});
} else if (!companyTelArea && companyTel) {
callback('请输入完整的固话');
setFields({
[phonefieldKey]: { value: companyTel, errors: null },
});
}
else if (companyTelArea && companyTel) {
setFields({
[areafieldKey]: { value: companyTelArea, errors: null },
[phonefieldKey]: { value: companyTel, errors: null },
});
callback();
}
callback();
}
render() {
const { areaNo, phoneNo, exNo } = this.state;
const { areafieldKey, phonefieldKey, exfiledKey, form: { getFieldDecorator } } = this.props;
return (
<Row gutter={10}>
<Col span={7}>
<Form.Item>
{getFieldDecorator(areafieldKey, {
initialValue: areaNo || undefined,
rules: [{ validator: this.checkFixedphone }],
validateTrigger: 'onBlur'
})(
<Input placeholder="请输入区号" />
)}
</Form.Item>
</Col>
<Col span={10}>
<Form.Item>
{(getFieldDecorator(phonefieldKey, {
initialValue: phoneNo || undefined,
rules: [{ validator: this.checkFixedphone }],
validateTrigger: 'onBlur',
getValueFromEvent: (event) => {
return event.target.value.replace(/\D/g, '')
},
})(
<Input placeholder="请输入固定电话号码" />
))}
</Form.Item>
</Col>
<Col span={7}>
<Form.Item>
{getFieldDecorator(exfiledKey, {
initialValue: exNo || undefined
})(
<Input placeholder="请输入分机号码" />
)}
</Form.Item>
</Col>
</Row>
);
}
}
export default FixedPhoneInput;
可以通过setFields
方法手动设置某个字段的报错信息为null
setFields({
[phonefieldKey]: { value:companyTel,errors: null },
});
另外一个就是客户账期的,当下拉选择货到付款
或者票到付款
的时候,后面的文本框展示.下拉选择款到发货
选项时候,影藏后面的文本框.
优化之后的账期组件: 只对Select下拉做onChange事件监听,文本框的值通过表单获取,父组件中引用传入form即可:
import React from 'react';
import { Input, Row, Col } from 'antd';
import BaseDictionary from 'components/BaseDictionary';
//客户账期下拉框,文本框组件
class AccountInput extends React.Component {
static getDerivedStateFromProps(props) {
if ('value' in props) {
return {
...(props.value || {}),
addonBeforeText: props.value.custPayType == 'PT_1' ? '货到' : '票到',
};
}
return null;
}
constructor(props) {
super(props);
const value = props.value || {};
this.state = {
custPayType: value.selectfieldKey || '', //账期方式列
custPayDate: value.inputfieldKey || '', //账期天数
addonBeforeText: ''
};
}
handleChangeVal = (type, value) => {
const { inputfieldKey } = this.props;
this.setState({ [type]: value }, () => {
//回调函数里面设置表单字段的值
value && value !== 'PT_2' && this.props.form.setFieldsValue({
[inputfieldKey]: `${value && value !== 'PT_2' ? '' : value}`,
});
});
this.triggerChange({
[type]: value,
addonBeforeText: value == 'PT_1' ? '货到' : '票到',
});
}
triggerChange = changedValue => {
const { onChange } = this.props;
console.log('changedValue', changedValue);
let accoutInfo = {
...this.state,
...changedValue
}
if (onChange) {
if (accoutInfo.custPayType === "PT_2") {
//选择款到发货,没有文本框的时候,返回对象没有custPayDate字段
onChange({
custPayType: accoutInfo.custPayType,
addonBeforeText: accoutInfo.addonBeforeText
})
} else if (accoutInfo.custPayType === undefined) {
//非必填项,清除操作,对应字段传入空值.
onChange({
custPayType: '',
addonBeforeText: ''
})
} else {
onChange({
custPayType: accoutInfo.custPayType,
custPayDate: accoutInfo.custPayDate,
addonBeforeText: accoutInfo.addonBeforeText
})
}
}
};
render(){
...
组件代码
...
}
}
render()函数代码:
每次切换账期方式的时候,后面文本框的值也进行了清空处理.(当然也可以进行必填的校验)
有时候,我们在页面一加载的时候,就要进行拿到异步的数据进行判断,然后进行设置改变setState操作. 这时候就需要我们在组件的componentDidMount
生命周期方法里面去执行异步方法.然后在.then
方法里面拿到异步返回的结果做判断: (因为我们无法知道何时异步操作请求完成)
例如判断客户账期,编辑操作的时候,(如果选中的是 货到付款
或者 票到付款
后面的天数必填),并且要添加必填标识:
新增(编辑)页面-->CustomerForm 组件->固话号码(客户账期)组件:
componentDidMount() {
const { customerId } = this.props;
customerId && this.getCustomerInfo(customerId);
}
getCustomerInfo = async (customerId) => {
let { code, data, msg } = await getCustomerDetail({ id:customerId });
if (code === "0") {
this.setState({
customerInfo: Object.assign({}, data)
}, () => {
this.isaccountRequired(customerId && this.state.customerInfo.custPayType !== "PT_2" ? true : false);
})
} else {
message.error(msg)
}
}
//客户账期是否需要必填
isaccountRequired = (value) => {
this.setState({
accountRequire: value
})
}
效果如下图:
父组件引用客户账期:
<FormItem label="客户账期">
{getFieldDecorator('custPay', {
initialValue:
customerbasicInfo && customerbasicInfo.id
? {
custPayDate: customerbasicInfo.custPayDate || '',
custPayType: customerbasicInfo.custPayType || undefined
}: ''
})(<CustomerAccountInput form={form} selectfieldKey="custPayType" inputfieldKey="custPayDate" />)}
</FormItem>
另外,对于动态表单值的提交,个人建议使用Antd封装好的方法来获取,不建议自己写onChange事件去监听,然后将当前的value值合并到每一条的对象里面.
{
title: '本次发货数量',
dataIndex: 'pickList',
width: 120,
render: (text, record, index) => (
<TableSellgoodsItem
form={form}
shipmentCount={record.unDeliverCount}
fieldKey={`pickList[${index}].deliverCount`}
placeholder="请输入发货数量"
/>
)
}
Comments
请在后台配置评论类型和相关的值。