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 通過自定義方法專門對入參做處理。