el-table + el-form 动态验证

202 阅读1分钟

需求

  1. 输入别名时,校验别名是否有重复,如果有,触发表单验证错误提示。

实现

<template>
  <div>
    <gdmp-input-with-search-icon clearable v-model="search"></gdmp-input-with-search-icon>
    <el-form ref="myForm" :model="formModel" style="display: flex">
      <BaseTable
        :data="formModel.list"
      >
        <el-table-column label="别名" prop="columnAlias">
          <template v-slot="scope">
            <el-form-item
              :prop="`list.${scope.$index}.columnAlias`"
              :rules="[
                { validator: formValidator }
              ]"
            >
              <el-input
                placeholder="请输入"
                :maxlength="10"
                clearable
                v-model="scope.row.columnAlias"
              ></el-input>
            </el-form-item>
          </template>
        </el-table-column>
      </BaseTable>
    </el-form>
  </div>
</template>

<script>
export default {
  name: 'GuideMode',
  data () {
    return {
      search: '',
      // 保存一份完整数据,过滤时用
      allList: [],
      search: '',
    }
  },
  computed: {
    filter_list () {
      if (this.search) {
        return this.allList.filter(item => {
          return item.columnName.toLowerCase().indexOf(this.search.toLowerCase()) !== -1
        })
      }
      return this.allList
    },
    formModel () {
      return {
        list: this.filter_list
      }
    }
  },
  methods: {
    formValidator (rule, value, callback) {
      if (value) {
        const { fullField } = rule // fullField => list.0.columnAlias
        const [,, prop] = fullField.split('.')
        const hasRepeat = this.formModel.list.filter(item => item[prop] === value).length > 1
        if (hasRepeat) {
          callback(new Error('别名重复'))
        } else {
          callback()
        }
      } else {
        callback()
      }
    },

    async searchList () {
      // 接口获取列表数据后
      this.allList = list
      this.formModel.list = list
    },

    handleSave () {
      this.$refs.myForm.validate(async valid => {
        console.log(valid)
        if (valid) {
        } else {
          this.$message.warning('存在别名重复,请修改后提交')
        }
      })
    }
  }
}
</script>

效果如下图:

到这里看似很完美,但是当你输入搜索条件时就会出现问题。

先看一下过滤条件的逻辑:

  computed: {
    filter_list () {
      if (this.search) {
        return this.allList.filter(item => {
          return item.columnName.toLowerCase().indexOf(this.search.toLowerCase()) !== -1
        })
      }
      return this.allList
    },
    formModel () {
      return {
        list: this.filter_list
      }
    }
  },

如果search发生变化,触发计算属性filter_list变化,返回符合条件的新数组,从而触发el-formmodel绑定的formModel属性变化,表格的data绑定的是formModel.list所以页面重新渲染。

当筛选结果渲染出来后,再输入别名,此时是在当前列表formModel.list中还是在allList中进行重复校验?这个在产品给的需求中是没有说的,所以只能靠我们开发人员来推断。

我认为是在allList中检测,很显然列表数据已经全部给到前端,过滤只是取出一部分,别名的重复校验的意思就是在全部数据中检测有没有重复的别名。

所以我们要修改formValidator中的代码:

   formValidator (rule, value, callback) {
      if (value) {
        const { fullField } = rule
        const [,, prop] = fullField.split('.')
        const hasRepeat = this.allList.filter(item => item[prop] === value).length > 1
        if (hasRepeat) {
          callback(new Error('别名重复'))
        } else {
          callback()
        }
      } else {
        callback()
      }
    },

效果如下图:

从前几张截图中我们看到,数据中是有别名为“管理员”的,但是上图筛选后的数据中没有“管理员”,此时照样可以触发“管理员”别名重复校验。