1. 程式人生 > 其它 >Element UI 針對迴圈表單巢狀表格校驗 解決方式

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