[Vuejs]-How to use Vuelidate in a nested form components hierarchy?

1šŸ‘

I think I found a way to achieve this.
Since iā€™m not comfortable with Vue, Iā€™m very open to comments and advices about this solution.

In the Form, I provide the vuelidate object but making it reactive using the computed function :

<!-- Form.vue -->
setup() {
    return {
        v$: useVuelidate(),
    }
},

provide() {
    return {
        v$: computed(() => this.v$) // NOTE : to make injections reactively linked to the provider, we need to provide a computed property using the computed() function + To make injections automatically unwrap computed refs in Vue < 3.3, we need to set app.config.unwrapInjectedRef to true.
    }
},

In this way, in could easily retrieve the vuelidate object (v$) using inject in the child component avoiding props drilling.

<!-- Input.vue -->
<template>
    <input
        type="text"
        v-model="modelLocal"
    >
    <span>{{ getErrors() }}</span>
</template>

<script>
export default {

    inject: ['v$'],

    emits: ['update:modelValue'],

    props: {
        modelValue: {
            required: true,
        },
        path: {
            required: true,
        },
    },

    computed: {

        modelLocal: {
            get() {
                return this.modelValue
            },
            set(value) {
                this.$emit('update:modelValue', value)
            }
        },

    },

    methods: {
        getErrors(){
            return this.v$.$errors ? this.v$.$errors.filter((item)=> item.$propertyPath === this.path).map(e => e.$message) : ''
        }
    }

}
</script>

Note that I also added a getErrors() method on the Input and added a prop "path" to know which error I have to retrieve from the vuelidate object.
The input is now called like that:

<Input
    v-model="data.field"
    path="data.field"
></Input>
šŸ‘¤Aurelien

Leave a comment