表单验证与回填以及表单常见bug解决方法
2019-10-30 本文已影响0人
家有饿犬和聋猫
import React, { Component } from 'react';
import styles from './addMessage.scss';
import {Input, Form, Table, message, Row, Col, Modal, Radio, Select, DatePicker, Button, Pagination} from 'antd';
import cns from 'classnames';
import bind from 'react-autobind';
import {isNotEmpty, addressNum} from 'utils/util'; // 封装的公用方法
import {getSession} from 'utils/storage';
import Bigmodal from './Modal';
import {service} from '../../../../services/messageManage';
import {getArea, userMsg} from '../../../../services/common';
import {getEnterpriseUserList} from '../../../../services/systemManage';
import Cookies from 'js-cookie';
const { TextArea } = Input;
// formItemLayout :表单行列格式
const formItemLayout = {
labelCol: { span: 6 }, // 左边留白大小
wrapperCol: { span: 17 } // 内容区大小(两者和不能!>24)
};
class addMessage extends Component {
constructor(props){
super(props);
this.state = {
title: '',
sendName: '',
allIndustry: '',
allCity: [],
allCounty: [],
content: '',
total: 0,
selected: '',
visible: false,
hint: '',
bigModal: false,
saveRequired: true, // 点“暂存”的时候 只验证标题
companyDataSource: [], // 企业列表
letterMsg: {},
selectedRows: [], // 选中的数据 回填
selectedKeys: [],
keys: 0
};
bind(this);
}
componentDidMount(){
this.industryArr();
this.getArea();
let type = addressNum(this.props).type;
if(type === 'editor'){
// 编辑或修改 回填信息
this.searchLetter();
}else {
// 新建 获取当前用户名
this.setState({
sendName: getSession('USERINFO').name
});
}
// 添加的时候获取企业列表
this.getEnterpriseUserList({name: ''});
// 企业总数不随筛选变化
getEnterpriseUserList({name: ''}).then(
rem=>{
if(rem.success && isNotEmpty(rem.data)){
this.setState({
total: rem.data.totalCount
});
}else{
this.setState({
total: 0
});
}
}
);
}
// 获取信息
searchLetter=()=>{
let id = addressNum(this.props).id;
service.searchLetter({id: id}).then(
rem=>{
if(rem.success){
// 获取收件人列表
let selectedRows = [];
if(isNotEmpty(rem.data.sendToList)){
let v = rem.data.sendToList;
let selectedKeys = [];
v.map(
p=>{
// p 是用户名id
selectedKeys.push(p.userId);
userMsg({userId: p.userId}).then(
msg=>{
if(msg.success){
selectedRows.push(msg.data);
}
}
).then(
()=>{
this.setState({
selectedRows: selectedRows, // 数据回填,选中的数据
selectedKeys
});
}
);
}
);
}
this.setState({
sendName: rem.data.createName,
selected: rem.data.sendToList.length
});
setTimeout(()=>{
this.props.form.setFieldsValue({
title: rem.data.name,
content: rem.data.content,
selected: rem.data.sendToList.length === 0 ? '' : rem.data.sendToList.length
});
}, 100);
}else{
this.setState({
letterMsg: {}
});
}
}
);
}
// 获取企业用户列表 弹框中的数据
getEnterpriseUserList=(params)=>{
getEnterpriseUserList(params).then(
rem=>{
if(rem.success && isNotEmpty(rem.data)){
this.setState({
companyDataSource: Array.isArray(rem.data.data) ? rem.data.data.map(
(p, index)=>{
let naso = JSON.parse(p.styleJson);
p['letterName'] = isNotEmpty(naso) ? naso.contactName : '';
p['key'] = `${p.id}`; //表格的key值设为id值,方便回显数据
return p;
}
) : []
});
}else{
this.setState({
companyDataSource: []
});
}
}
);
}
// 提交审核
handleSubmit=(e)=>{
e.preventDefault(); // 阻止默认刷新
this.props.form.validateFields((err, values) => {
const{title, content, selected} = values; //validateFields()获取输入值,从state传回到表单,双向绑定
this.setState({
title,
content,
selected
});
if (!err) {
//验证通过时,调接口发送数据
let id = addressNum(this.props).id;
let params = {
id: id ? id : '', // number 如果有id,为修改信,没有为新增信
content,
name: title,
sendToList: this.state.selectedRows.map(
p=>p.id
)
};
service.toSubmit(params).then(
rem=>{
if(rem.success){
this.setState({
visible: true,
hint: '站内信提交成功!'
});
}
}
);
}
});
};
// 暂存
zanCun=(e)=>{
//不需要验证通过时,直接获取表单值
const values = this.props.form.getFieldsValue();
const{title, content} = values;
const {selectedKeys} = this.state;
let id = addressNum(this.props).id;
if(title){
let params = {
id: id ? id : '', // number 如果有id,为修改,没有为新增
content,
name: title,
sendToList: selectedKeys
};
service.toSave(params).then(
rem=>{
if(rem.success){
this.setState({
visible: true,
hint: '站内信暂存成功!'
});
}
}
);
}else{
message.warning('标题必填');
}
};
// 取消
cancel=()=>{
this.props.history.push('/systemManage/messageManage/message');
}
littleOk=()=>{
this.props.history.push('/systemManage/messageManage/message');
}
littleCancel=()=>{
this.setState({
visible: false
});
}
// 已选择的企业
selectedData=(e)=>{
this.setState({
bigModal: false,
selected: e.selectedRows.length,
selectedRows: e.selectedRows,
selectedKeys: e.selectedKeys
});
//数据回填时,需要在表单渲染完毕之后赋值,否则会报错,所以使用一个setTimeout
setTimeout(
()=>{
this.props.form.setFieldsValue({
selected: e.selectedRows.length === 0 ? '' : e.selectedRows.length
});
}, 30
);
}
showBigModal=(e)=>{
this.setState({
bigModal: true,
keys: Number(this.state.keys) + 1
});
}
render() {
let {total, title, content, keys, saveRequired, sendName, visible, selected, bigModal, hint} = this.state;
const { getFieldDecorator } = this.props.form;
return (
<div className={styles.addMessage}>
<div className={'titLine'}>添加站内信</div>
<div className={styles.FormBox}>
<Form onSubmit={this.handleSubmit.bind(this.props.form)} >
<Row> //form表单需要用Row Col 包起来,否则 formItemLayout 不生效
<Col>
<Form.Item label="发件人" {...formItemLayout}>
{getFieldDecorator('ema', {
rules: [
{
required: false
}
]
})(<span>{sendName}</span>)}
</Form.Item>
</Col>
</Row>
<Row>
<Col>
<Form.Item label="标题" {...formItemLayout} >
{getFieldDecorator('title', {
initialValue: title,
rules: [
{
required: true,
message: '请输入标题!'
}
]
})(<Input />)}
</Form.Item>
</Col>
</Row>
<Row>
<Col>
<Form.Item label="内容" {...formItemLayout}>
{getFieldDecorator('content', {
initialValue: content,
rules: [
{
required: saveRequired,
message: '请输入内容!'
}
]
})(<TextArea rows={4} />)}
</Form.Item>
</Col>
</Row>
<Row>
<Col>
<Form.Item label="收件人" {...formItemLayout}>
{getFieldDecorator('selected', {
initialValue: selected === 0 ? '' : selected, //自定义表单值
rules: [
{
required: saveRequired,
message: '请选择收件人!'
}
]
})(<p><Button onClick={this.showBigModal} className={'red-btn'} >选择</Button>  <span>共有{total}家企业,已选择<span style={{color: '#0C61B7'}}> {selected ? selected : 0} </span>家</span></p>)}
</Form.Item>
</Col>
</Row>
<div className="longLine"> </div>
<div className={styles.botDiv}>
<Button className="red-btn" htmlType="submit" >提交审核</Button>
<Button className="blue-btn" onClick={this.zanCun.bind(this.props.form)}>暂存</Button>
<Button className="cancel-btn" onClick={this.cancel}>取消</Button>
</div>
</Form>
</div>
<Modal
title="系统提示"
wrapClassName="littleModal"
visible={visible}
onCancel={this.littleCancel}
footer={null}
>
<div style={{textAlign: 'center'}}>
<img src={require('../../../../images/success.svg')} />
<p className="hint" >{hint}</p>
<div className="btndiv" >
<Button className="red-btn" onClick={this.littleOk}>确定</Button>
</div>
</div>
</Modal>
{
bigModal ?
<Bigmodal selectedData={this.selectedData} keys={keys} {...this.state} getEnterpriseUserList={this.getEnterpriseUserList} camcelModal={this.camcelModal} />
:
''
}
</div>
);
}
}
export default Form.create()(addMessage);
image.png
表单的验证
正则验证 pattern
<Form.Item hasFeedback validateStatus={ !disabled ? 'success' : ''} >
{getFieldDecorator('projectName', {
initialValue: projectName,
rules: [
{ required: true, message: '请输入项目标题' }, //required为true表示必填项,false表示选填项
{pattern: /\s\S+|S+\s|\S/, message: '标题不能全为空格'}
]
})(
<Input className={cns(styles.comInt)} placeholder="请输入项目标题" onChange={this.projectName} />
)}
</Form.Item>
自定义验证validator
{getFieldDecorator('declareStartTime', {
initialValue: declareStartTime,
rules: [{ required: true, message: '请选择开始日期和时间' },
{ validator: (rule, value, callback) => {
if (value > this.props.form.getFieldsValue().declareEndTime) {
callback('起始时间不能大于结束时间');
}
callback();
}}]
})
表单注意事项
~获取值,使用getFieldsValue(),获取出来的是所有值,数据类型为对象,需要自己结构
this.props.form.getFieldsValue()
~设置值 ,使用 this.props.form.setFieldsValue({a:"1" }) ,但是他有一个bug,数据回填较慢,导致操作的时候数据为空, 如果需要实时操作,可以把数据存在state了,然后在函数中操作
~表单提交时,页面刷新,数据消失
解决方法就是 使用 e.preventDefault();
image.png
image.png
参数e最好从提交的时候绑定this.props.form
~点击button提交表单
两种方式:
1
<Button type="primary" className={cns(styles.view)} onClick={this.handleSubmit.bind(this.props.form)}>预览</Button>
2
<Form onSubmit={this.handleSubmit.bind(this.props.form)} >
<Button className="red-btn" htmlType="submit" >提交审核</Button>
// htmlType="submit"
如果一个表单,有几个提交按钮,可以添加key值区分
onClick={this.handleSubmit.bind(this.props.form , key)}
3
两个地方联动验证
比如先输入了开始时间(验证报错),再输入结束时间,输入完结束时间需要验证开始时间,去掉开始时间验证的报错,可以使用setFilesValues({}),它在赋值的时候会做验证
<Form.Item>
{getFieldDecorator('declareEndTime', {
initialValue: declareEndTime,
rules: [{ required: true, message: '请选择结束日期和时间' },
{ validator: (rule, value, callback) => {
this.props.form.setFieldsValue({declareStartTime }); //赋值完后,表单自动验证起始时间
if (value < this.props.form.getFieldsValue().declareStartTime) {
callback('起始时间不能大于结束时间');
}
callback();
}}
]
})(
<DatePicker placeholder="请选择结束日期和时间"
disabled = {disabled}
onChange={(v)=>{ this.setState({declareEndTime: v});}} //提前将值保存起来,方便联动验证的时候赋值
showTime />
)}
</Form.Item>