Element UI 针对循环表单嵌套表格校验 解决方式
最近有一个分单的需求,需要把一个二维数组通过表单提交传参给后台。
主要数据格式(数组[对象{对象,数组},对象{对象,数组}])示例 this.ruleList:
[{ info: { name: '1', paymentTerm: '', stockPosition: '', purchaseGroup: '', }, materialList: [{ a: '', b: '', deliveryDate: '2022-3-20' }, { a: '', b: '', deliveryDate: '2022-3-20' } ] }, { info: { name: '2', paymentTerm: '', stockPosition: '', purchaseGroup: '', }, materialList: [{ a: '', b: '', deliveryDate: '2022-3-20' }] } ]
数据处理部分代码示例:
this.ruleDataList.forEach(item=>{ this.$set(item.info,'materialList',item.materialList); item.materialList.forEach(ele=>{ this.$set(ele,'defaultDate',ele.deliveryDate); this.$set(ele,'rule',[ { required: true, validator:(rule, value, callback)=>{ this.deliveryDate(rule,callback,ele.defaultDate,ele.deliveryDate) }, trigger: ['blur','change'] } ]) }) this.validateList.push(item.info) })
首先将this.ruleDataList 里的对象和数组都合并到info里,materialList数组里新增了两个属性值rule和defaultDate并push到一个新数组validateList里,这样我们就得到this.validateList的数据格式为:
{ name: '1', paymentTerm: '', stockPosition: '', purchaseGroup: '', materialList: [{ a: '', b: '', deliveryDate: '2022-3-20', rule: '表格项校验规则' }, { a: '', b: '', deliveryDate: '2022-3-20', rule: '表格项校验规则' } ] }, { name: '2', paymentTerm: '', stockPosition: '', purchaseGroup: '', materialList: [{ a: '', b: '', deliveryDate: '2022-3-20', rule: '表格项校验规则' }] } ]
这样我们渲染页面时就可以直接用处理后的数组,更方便表单的校验。页面通过v-for来循环validateList,获得多个表单,所以表单的ref拼接了索引,页面代码示例如下:
<div class="separateContent"> <el-row class="soDetailRow" v-for="(item,index) in validateList" :key="index"> <div class="subTitle"> <span>{{item.supplierName}}</span> </div> <el-form :model="item" :ref="'ruleForm'+index" label-width="100px"> <el-form-item label="付款条件:" prop="paymentTerm" :rules="[{ required: true, message: '付款条件不能为空'}]" class="formRow"> <el-select placeholder="请选择" filterable style="width:200px;margin-right:10px" v-model="item.paymentTerm"> <el-option v-for="ops in paymentClauseList" :key="ops.value" :label="ops.label" :value="ops.value"> </el-option> </el-select> </el-form-item> <el-table border :row-class-name="tableRowClassName" :header-cell-style="{background: '#f7f7f7',padding:'5px 10px'}" ref="multipleTable" :data="item.materialList"> <el-table-column align="center" prop="orderUnitDesc" label="单位" ></el-table-column> <el-table-column align="center" prop="deliveryDate" label="交货期" min-width="130px"> <template slot-scope="scope"> <el-form-item :prop="'materialList.'+scope.$index+'.deliveryDate'" :rules="scope.row.rule" class="costValue"> <el-date-picker :clearable="false" style="width:130px" @change="handleChangeDate(scope.row,`materialList.${scope.$index}.deliveryDate`,`${index}`,)" v-model="scope.row.deliveryDate" type="date" value-format="yyyy-MM-dd" :placeholder="`选择日期${index}`"> </el-date-picker> </el-form-item> </template> </el-table-column> </el-table> </el-form> </el-row> </div> <el-row class="crumbs btns printBtns" type="flex" justify="center"> <el-button class="el-btn" @click="hanldeCheckForm('1')" v-preventReClick>存为待推送</el-button> <el-button type="primary" class="el-btn" @click="hanldeCheckForm('2')" v-preventReClick>确认分单</el-button> </el-row>
由于表单是多个,表单里嵌套的表格也是多个,根据prop定义的动态表单校验会有重复值,所以在处理数组时,set了每一项的自定义校验规则(每项的交货期日期组件选择都不能小于默认日期),规则代码如下:
// 自定义日期校验 deliveryDate(rule, callback,defaultDate,deliveryDate){ let index = Number(rule.field.split('.')[1])//获取当前验证项的index,对应数据的index if(!deliveryDate){ callback(new Error('交货日期不能为空')) }else if(defaultDate > deliveryDate){ callback(new Error('只能选择'+ defaultDate +'之后的日期')) }else{ callback() } },
表单提交时,由于是多个表单,只有所有的表单校验通过之后再去请求接口,这里用到的是Promise.all的方法,代码示例如下:
// 表单校验 hanldeCheckForm(type){ let _self = this; let newArr = []; this.validateList.forEach((item,index)=>{ let result = new Promise(function(resolve, reject) { _self.$refs['ruleForm'+index][0].validate(valid=>{ if (valid) { resolve(); } else { reject() } }) }) newArr.push(result); }) Promise.all(newArr).then(function() { //都通过了 let paramsList = []; _self.validateList.forEach(item=>{ paramsList.push({info:item,materialList:item.materialList}) }) if(type == '1'){ _self.handlePushClick(paramsList) }else{ _self.handleConfirmClick(paramsList) } }).catch(function(err) { console.log(err); }) }, // 待推送 handlePushClick(params){ saveWaitPush(params).then(res=>{ if(res.code == '200'){ this.$message({ message: '操作成功', type: 'success' }); this.$emit('handleClose',false,true) } }) }, // 待确认 handleConfirmClick(params){ confirmSplit(params).then(res=>{ if(res.code == '200'){ this.$message({ message: '操作成功', type: 'success' }); this.$emit('handleClose',false,true) } }) },
由于后台要求入参格式跟未处理之前一致,所以在接口请求之前又重新将对象和数据剥离成 paramsList.push({info:item,materialList:item.materialList})。这里没有专门对info里的materialList做删除处理,可以自行删除。
解决需求痛点:
1.循环(多)表单动态校验。
2.自定义校验传参validator入参无法接收rule, value, callback 之外的参数,导致表格项校验时,无法直接通过索引值获取数组里的某一项做校验,曲线救国通过set以及在validator 通过自定义方法专门对入参做处理。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)