Syed
Syed

Reputation: 16513

How to make Vue's element-ui validateField() works with v-if?

Please look at password fields. Password and Confirm Password fields shows when Change Password? button is clicked.

Below code works fine and validates the form as expected with v-show but does not validates when v-if is used.

I understand what v-show and v-if does, and the functions in data(){} that's how it's in element-ui's doc. Here is the doc's url: http://element.eleme.io/#/en-US/component/form#custom-validation-rules

<template lang="pug">
  el-dialog( width="600px", title="Users", :visible.sync="dialogVisible")
    el-form.demo-ruleForm(:model="editedItem", status-icon, :rules="formRules", ref="userForm", label-width="140px")
      el-form-item(label="Name", prop="firstName")
        el-input(v-model="editedItem.name", auto-complete="off")

      template(v-if="!changePassword")
        el-form-item
          el-button(@click="changePassword = true") Change Password?
      template(v-else)
        el-form-item(label="Password", prop="password")
          el-input(type="password", v-model="editedItem.password", auto-complete="off")

        el-form-item(label="Confirm Password", prop="confirmPassword")
          el-input(type="password", v-model="editedItem.confirmPassword", auto-complete="off")

    .dialog-footer(slot="footer")
      el-button(type="primary", @click="submitForm('userForm')") Save
</template>

<script>
export default {
  name: 'dialog-add-edit-user',
  props: {
    editedItem: Object,

  },
  data () {
    const validatePass = (rule, value, callback) => {
      if (value === '') {
        callback(new Error('Please input the password'))
      } else {
        if (this.confirmPassword !== '') {
          this.$refs.userForm.validateField('confirmPassword')
        }
        callback()
      }
    }

    const validatePass2 = (rule, value, callback) => {
      if (value === '') {
        callback(new Error('Please input the password again'))
      } else if (value !== this.editedItem.password) {
        callback(new Error('Two inputs don\'t match!'))
      } else {
        callback()
      }
    }

    return {
      formRules: {
        password: [
          {
            validator: validatePass,
            trigger: 'blur'
          }
        ],
        confirmPassword: [
          {
            validator: validatePass2,
            trigger: 'blur'
          }
        ]
      },
      dialogVisible: false,
      changePassword: false,
      editedItem: {
        name: '',
        password: '',
        confirmPassword: ''
      }
    }
  },

  methods: {
    submitForm (formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          this.$emit('save-item')
          console.log('submit!')
        } else {
          console.log('error submit!!')
          return false
        }
      })
    }
  }
}
</script>

Upvotes: 0

Views: 7377

Answers (1)

Daniel
Daniel

Reputation: 35704

Ok, I think I understand what the issue is.

your validation is passing, but it's not checking name and password, only passwordChange.

so if you "... understand what v-show and v-if does" you'll know that the elements do not exist when you use v-if/v-else. They get added and removed as needed.

The reason this is a problem is that the element library goes through a initialization stage when they get added. The element gets referenced later using $ref. look at SubmitForm, it uses `this.$refs[formName].validate'

so when you use v-if/v-else, because the elements were not there to begin with, they will not be called properly.

you have two options, either stick with v-show, which should be easy enough, or you can use a hack I've been exploiting with 3rd party libraries that don't allow forcing a manual or auto reload. The hack consists of adding a key to the main element. So the html would look like this.

<el-form
  class="demo-ruleForm"
  :model="editedItem"
  status-icon="status-icon"
  :key="'form'+changePassword"  <--- this is the magic
  :rules="formRules"
  ref="userForm"
  label-width="140px"
>

and in pug

el-form.demo-ruleForm(:model="editedItem", :key="'form'+changePassword", status-icon, :rules="formRules", ref="userForm", label-width="140px")

Upvotes: 1

Related Questions