Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Vee Validate - Child Component Example
import Vue from 'vue';
const bus = new Vue();
export default bus;
<template>
<div>
<input v-validate data-rules="required" :class="{'has-error': errors.has("textInput")}" id="textInput" name="textInput" type="text">
<span class="error" v-show="errors.has("textInput")">{{ errors.first("textInput") }}</span>
</div>
</template>
<script>
import { find, propEq } from 'ramda'
import bus from './bus'
export default {
mounted() {
//Listen on the bus for the parent component running validation
bus.$on('validate', this.onValidate)
//Watch for the changes to the childs error bag and pass back to the parent
this.$watch(() => this.errors.errors, (newValue, oldValue) => {
const newErrors = newValue.filter(error =>
find(propEq('field', error.field))(oldValue) === undefined
)
const oldErrors = oldValue.filter(error =>
find(propEq('field', error.field))(newValue) === undefined
)
bus.$emit('errors-changed', newErrors, oldErrors)
})
},
methods: {
onValidate() {
this.$validator.validateAll();
if (this.errors.any()) {
bus.$emit('errors-changed', this.errors.errors)
}
},
},
beforeDestroy() {
//When destroying the element remove the listeners on the bus.
//Useful for dynaically adding and removing child components
bus.$emit('errors-changed', [], this.errors.errors)
bus.$off('validate', this.onValidate)
},
}
</script>
<template>
<div>
<child-component></child-component>
<button :disabled="errors.any()" :click="submit()"></button>
</div>
</template>
<script>
import bus from './bus'
import ChildComponent from './ChildComponent'
export default {
mounted() {
//Emit that validation is required on the bus
this.$on('veeValidate', () => {
bus.$emit('validate');
})
//Listen on the bus for changers to the child components error bag and merge in/remove errors
bus.$on('errors-changed', (newErrors, oldErrors) => {
newErrors.forEach(error => {
if (!this.errors.has(error.field)) {
this.errors.add(error.field, error.msg)
}
})
if (oldErrors) {
oldErrors.forEach(error => {
this.errors.remove(error.field)
})
}
})
},
methods: {
submit() {
//On button pressed run validation
this.$validator.validateAll()
if (!this.errors.any()) {
//Do Sumbit
}
}
}
components: {
ChildComponent,
},
};
</script>
Owner

sproogen commented Nov 9, 2016

This is an example of Child Component Validation for Vee Validate (https://github.com/logaretm/vee-validate).

For real use all the methods in the child component could be added using a Vue Mixin (https://vuejs.org/v2/guide/mixins.html) to prevent duplicating it in every child component.

@sproogen
Do you have an example to solve this problem by using vuex?

Owner

sproogen commented Jan 19, 2017

@bigperson no I do not. We are using vuex in this project but I did not think we should use it for storing anything in the state.

It would be possible to store the error bag in the state, but this would need some re-writing of vee-validate.

polunzh commented Feb 13, 2017

@sproogen
When trigger veeValidate event in parent component?

Hi, I'm trying to use this example but VeeValidation is not being triggered. Nothing happens when I hit submit. I could build all child validations, but I'm stuck on the submit stuff. How would I check the current validation to then submit the form? tks

cdarken commented Apr 4, 2017

@sproogen mate, the line here https://gist.github.com/sproogen/147d75db261505e8a558a7fd11a20551#file-parentcomponent-vue-L16 is a bit misleading because at https://gist.github.com/sproogen/147d75db261505e8a558a7fd11a20551#file-parentcomponent-vue-L36 you're using this.$validator. Can you update the gist to be a bit more clear, please ?

Is there any way to make the errors object global? Would make things easier.

I can't get this working... validateAll() is a promise, so I don't really see how this should work

lehni commented May 4, 2017

@sproogen I believe I found a simpler way to address this situation, see logaretm/vee-validate#468 (comment)

At the moment, this requires a bit of hacking with the internals of vee-validate to remove the beforeCreate() and mounted() hooks, but maybe this pattern can find its way into the library...

I tried for 6 hours to get this working with my app (as I have deeply nested components). Eventually, I just used this Advanced -
Inject
and had it solved in 3 minutes flat. If you can't get the above to work, try the injection route!

lattam commented Jul 5, 2017

@stephenmac that's perfect, thanks! One line in child component solves everything (I have a form with several sub-form components).

inject: ['$validator']

@lattam this not worked for me... any idea?

Simply adding that single line @lattam talks about didn't work for me either. I also had to do Vue.use(VeeValidate, { inject: false }); and manually set the validator on the parent element with: $validates: true,

I add inject: ['$validator'] in child component but show a warning Injection "__ob__" not found

imjeen commented Sep 7, 2017

vee-validate@2.0.0-rc.14:
this.errors.errors should be this.errors.items

pymarco commented Sep 8, 2017

I get Injection "__ob__" not found too, the same as @woodyalan.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment