Element 表格中添加动态表单验证的实现与BUG

[TOC]

Table中添加动态表单验证

初始.png
新增一行编辑.png

效果如上图所示,最开始table为空,然后新增一行后进行编辑,失去焦点后触发规则校验。

关键代码如下

<template>
    <div >
      <el-button @click="handleAdd">新增</el-button>
      <el-button @click="handleDelete">删除</el-button>
      <el-form :rules="model.rules" :model="model"  ref="form">
          <el-table
          border
          @selection-change="handleSelectionChange"
          ref="multipleTable"
          :data="model.tableData"
          style="width: 200px;"
          >
          <el-table-column
          type="selection"
          width="50"
          align="center"
        ></el-table-column>
          <el-table-column
              width="100px"
              label="要求批次">
              <template slot-scope="scope">
                      <el-form-item :prop="'tableData.' + scope.$index + '.name'" :rules='model.rules.name'>
                          <el-input style="width:80px"  v-model="scope.row.name" ></el-input>
                      </el-form-item>
              </template>
          </el-table-column>
          </el-table>
      </el-form>
    </div>
</template>
<script>
export default {
  name: 'Page404',
  data(){
    return {
      model:{
        tableData:[],
        multipleTable:[],
        rules:{
          name:[{ required: true, message: '请输入', trigger: 'blur' },]
        }
      }
    }
  },
  methods:{
    handleAdd(){
      this.model.tableData.push({
        name:"",
      })
    },
    handleDelete(){
      let {multipleTable} = this;
      this.model.tableData = this.model.tableData.filter(item => {
        // 对比vue 数组内置的id号当做行号
        return !multipleTable.find(i => i.__ob__.dep.id === item.__ob__.dep.id);
      });
    },
    handleSelectionChange(val){
      this.multipleTable = val;
    }
  },
}
</script>

解析:其实问题关键就在于如何给el-form-item动态绑定prop,然后,:prop="'tableData.' + scope.$index + '.字段名'",最后把规则也绑定上:rules='model.rules.name'

其实到此为止都还是比较简单,网上到处都有。但是下面是我碰到的一个坑,也搞了好久才定位到问题。

Table中添加表单验证动态删减后规则没有重新校验

错误结果如下图:途中明显我已经有值了,但还是标红,为啥呢?

结果通过校验的行也标红了.png

复现步骤:
1.空table
2.直接新增两行
新增两行.png

3.触发两行的规则,使标红(此处因为我是通过失焦来触发)


触发两行的规则校验.png

4.勾选第一行,点击删除按钮


删除第一行.png

5.得到不是我们想要的结果
结果通过校验的行也标红了.png

分析

网上找了下,发现并没有看到类似问题描述,我自己猜测应该是:prop="'tableData.' + scope.$index + '.name'"scope.$index的原因,原来两行分别是0,1,现在删除后只有一行就是0,导致没有重新触发规则校验。

解决思路

想了许久,还是决定手动触发table的重新渲染,最简单的方式就是通过v-if来整个重新渲染table。关键代码就是在删除操作前后手动触发table清除和显现。下面是完整代码:

<template>
    <div >
      <el-button @click="handleAdd">新增</el-button>
      <el-button @click="handleDelete">删除</el-button>
      <el-form :rules="model.rules" :model="model"  ref="form">
          <el-table
          v-if="tableVisible"
          border
          @selection-change="handleSelectionChange"
          ref="multipleTable"
          :data="model.tableData"
          style="width: 200px;"
          >
          <el-table-column
          type="selection"
          width="50"
          align="center"
        ></el-table-column>
          <el-table-column
              width="100px"
              label="要求批次">
              <template slot-scope="scope">
                      <el-form-item :prop="'tableData.' + scope.$index + '.name'" :rules='model.rules.name'>
                          <el-input style="width:80px"  v-model="scope.row.name" ></el-input>
                      </el-form-item>
              </template>
          </el-table-column>
          </el-table>
      </el-form>
    </div>
</template>
<script>
export default {
  name: 'Page404',
  data(){
    return {
      tableVisible:true,
      model:{
        tableData:[],
        multipleTable:[],
        rules:{
          name:[{ required: true, message: '请输入', trigger: 'blur' },]
        }
      }
    }
  },
  methods:{
    handleAdd(){
      this.model.tableData.push({
        name:"",
      })
    },
    handleDelete(){
      this.tableVisible = false;
      let {multipleTable} = this;
      this.model.tableData = this.model.tableData.filter(item => {
        // 对比vue 数组内置的id号当做行号
        return !multipleTable.find(i => i.__ob__.dep.id === item.__ob__.dep.id);
      });
      //如果没有$nextTick,就不会生效,这样强制保证在下个循环来显示table
      this.$nextTick(()=>{
        this.tableVisible = true;
      })
    },
    handleSelectionChange(val){
      this.multipleTable = val;
    }
  },
}
</script>

ok,解决问题。如果有更优雅的方式解决或者问题原因定位欢迎交流和指教。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。