2
votes

I am trying to use VeeValidate in a custom input component.

I tried using $emit on @input and @blur but the validation occurs on next tick and i end up failing to catch the validation on event.

  onEvent (event) {
    console.log('error length', this.errors.items.length)
    if (this.errors.items.length) {
      this.hasError = true
      this.$emit('has-error',this.errors.items)
    } else {
      this.hasError = false
      this.$emit('on-input', event)

    }
  }

I also tried injecting the validator from the parent so as to be able to access the errors computed property directly but there might be 1-2-3 levels of nesting between the parent page and the custom input component itself. I would have to inject the validator through all of them and these component are meant to be reusable.

 export default {
   //in custom input component
   inject: ['$validator'],
 }

The best idea i got is to watch the errors computed property and emit an event when a change occurs whit the errors in that instance of the component.

watch: {
  errors: function (errorsNew) {
    console.log('errors watch',errorsNew)
  }
},

The problem is that i can't seem to watch the errors computed property introduced by vee-validate.

Some simplified version of code:

parent

<template>
  <div id="app">

    <CustomInput
      :label="'Lable1'"
      :value="'value from store'"
      :validations="'required|max:10|min:5'"
      :name="'lable1'"
    />
    <button>Save</button>
  </div>
</template>

<script>
import CustomInput from "./components/CustomInput";

export default {
  name: "App",
  components: {
    CustomInput
  }
};
</script>

CustomInput

<template>
   <div>
     <label >{{ label }}</label>
     <input :value="value" :name="name" v-validate="validations">
     <span v-if="this.errors.items.length">{{this.errors.items[0].msg}}</span>
  </div>

</template>

<script>
export default {
  name: "HelloWorld",

  props: {
    label: {
      type: String,
      required: true
    },
    value: {
      type: String,
      default: ""
    },
    validations: {
      type: String,
      default: ""
    },
    name: {
      type: String,
      required: true
    }
  },

  watch: {
    errors: function(errorsNew) {
      console.log("errors watch", errorsNew);
      this.$emit('has-error')
    }
  }
};
</script>

Can someone please help me access the validation errors from the custom input?

Update

I created a simple fiddle if anyone finds it easier to test it https://codesandbox.io/s/mqj9y72xx

1

1 Answers

0
votes

I think the best way to handle this is to inject $validator into the child component. That seems to be how the plugin recommends it be done: https://baianat.github.io/vee-validate/advanced/#injecting-parent-validator.

So, in your CustomInput, you'd add inject: ['$validator'],.

Then, in the App.vue, you can have this in the template:

<div>
  These are the errors for "lable1" in App.vue:
     <span v-if="errors.has('lable1')">{{errors.first('lable1')}}</span>
</div>

I think that's really it.

Working example based off your example: https://codesandbox.io/s/pw2334xl17

I realize that you've already considered this, but the inject method searches up the component tree until it finds a $validator instance, so perhaps you should disable automatic injection in your app at the root level, thus every component searching for a validator to inject will all get that one. You could do that using:

Vue.use(VeeValidate, { inject: false });