I have forms components all over my application which emit on my Bus the "name" when the value is changed : Events.$emit(this.name, this.savedValue);
Then, on the parent component, I listen for the change (I couldn't use the v-model for some reasons at the time) like this:
Events.$on('myName', (value) => {
this.myData.name = value;
});
I would ideally like to add the validator on the parent level - ie. on my custom component:
I can't make the listen work here. What would be the best way?
Any help would be appreciated.
Thanks.
I can't help much without an example, as there are multiple solutions. First you may need to tell your subcomponent to inherit the validator from their parent which should make it easier to validate them using the Inject API.
When they will receive the validator from their parent, meaning they have access to the same fields and errors
// your component ctor options.
export default {
inject: ['$validator']
};
Now since your components have access to the parent validator object as their own, they can either register themselves as fields, or register some inputs inside them, depending on how your components look like.
export default {
created () {
// attach field
this.$validator.attach({
name: this.name, // or whatever the field name is
rules: 'required',
getter: () => {
return this.myData.value; // or whatever the value path is.
}
});
// add bus listener
Events.$on('myName', (value) => {
this.myData.name = value;
this.$validator.validate(this.name).then(result => {
// do stuff
});
});
}
};
Again I might complicate things here, if you can provide a minimal example in a fiddle I would be happy to help more.
Hi,
thanks for your help here - really appreciated.
And I'd register in the parent component (I mean where I have my app-input) the inject: ['$validator'], right ?
Regarding the second part of your comment, why can I use the v-validate inline in my app-input in the parent ?
Basically, my Vue files looks like (simplified) the following.
The component containing the form:
https://gist.github.com/bdebever/7e71425ac5d80546bb64c2a15ed48422
and the input component:
https://gist.github.com/bdebever/e8f50e4e8990ec8bcafd712bbc97efdc
thanks.
You can disregard the second part. I assumed you didn't want to use the v-validate directive.
You don't have to do any registration now, the directive will take care of these things. What inject does is to let the input component inherit the same validator as their parent, thats it. So if it validates itself the errors will appear in the parent component as well.
Now when the value changes by an external event, you can just call this.$validator.validate('fieldName') and errors will appear in the parent errors as well.
Hi, okay it worked.
I have an issue though - when the instance is mounted, even if there is already a value, the error is displayed "this field is required". So it doesn't take into account a pre-existing value.
Can you help?
thanks;
You can provide the value as the second parameter, since it doesn't detect it properly.
this.$validator.validate('fieldName', inputValue);
In the mounted/created instance?
Whenever the value changes, in your listener for example and if you are validating initially then in the created cycle listener as well.
The problem is that in the created hook, my component isn't fully mounted - so it throws an error, and in the mounted the value isn't passed.
Any other idea?
I am trying to use vee-validate with custom bootstrap input wrapper (https://bootstrap-vue.js.org/docs/components/form-input) and found that it's not fully integrated because it need to listen native events in order to get notified on blur (https://vuejs.org/v2/guide/components.html#Binding-Native-Events-to-Components).
My workaround is to call validation explicitly in submit handler:
<script>
export default {
data() {
return {
form: {
email: ''
},
submiting: false
}
},
methods: {
onSubmit(e) {
e.preventDefault();
this.$validator.validateAll();
if (this.errors.any()) {
console.log('errors!!!');
return;
}
this.submiting = true;
axios.post('/contact', this.form).then((response) => {
this.submiting = false;
if (response.errors) {
console.log(response.errors); // TODO: append to this.errors
} else {
console.log('Success!'); // TODO: redirect to another screen
}
});
}
}
};
</script>
<template>
<div>
<b-form @submit="onSubmit" class="mx-lg-5" novalidate>
<b-form-group id="emailGroup" label="Email address" label-for="email" >
<b-form-input id="email"
type="email"
name="email"
v-model="form.email"
placeholder="Your e-mail"
required
v-validate="'required|email'"
:state="fields.email.validated ? !errors.has('email') : null" />
<div v-show="errors.has('email')" class="invalid-feedback">{{ errors.first('email') }}</div>
</b-form-group>
<b-button type="submit" variant="primary" :disabled="submiting || errors.any()">Submit</b-button>
</b-form>
</div>
</template>
Any suggestion on how to fix it properly? Sorry, I am new in vue.js so maybe I am missing something.
@rzaharenkov
If the component does not emit the blur event then you cannot validate it on blur unfortunately, if your solution works then stick with it. You might consider building your own components if you want to overcome the 3rd party components limitations.
Closing since the issue is not related to vee-validate but rather to the app logic
Most helpful comment
I can't help much without an example, as there are multiple solutions. First you may need to tell your subcomponent to inherit the validator from their parent which should make it easier to validate them using the Inject API.
When they will receive the validator from their parent, meaning they have access to the same fields and errors
Now since your components have access to the parent validator object as their own, they can either register themselves as fields, or register some inputs inside them, depending on how your components look like.
Again I might complicate things here, if you can provide a minimal example in a fiddle I would be happy to help more.