Search code examples
vue.jsvee-validatevue-composition-api

How to use composition API with custom field in Vee Validate 4 correctly


After reading documentation of Vee Validate 4 about using composition api with custom inputs, do I understand correctly that hook useField a have to call only inside input component(in my example is VInput.vue)? Is any way that i can use hook functionality in parent component? The VInput is used for another functionality that don't need validation so it will be extra functionality add useForm for global component in out project For example I have List.vue

<template>
 <form class="shadow-lg p-3 mb-5 bg-white rounded" @submit.prevent="submitPostForm">
        <VFormGroup label="Title" :error="titleError">
            <VInput v-model="postTitle" type="text" name="title" />
        </VFormGroup>
        <VFormGroup label="Body" :error="bodyError">
            <VInput v-model="postBody" type="text" name="body" />
        </VFormGroup>
        <button type="submit" class="btn btn-primary">Submit</button>
    </form>
</template>

<script>
import { ref, onMounted } from 'vue';
import { Form, useForm, useField } from 'vee-validate';
import * as Yup from 'yup';

export default {
    components: { Form },

    setup() {    
        const schema = Yup.object().shape({
           title: Yup.string().required(),
           body: Yup.string().min(6).required(),
        });

       //hooks
       const { handleSubmit } = useForm({ validationSchema: schema });

       // No need to define rules for fields because of schema
       const { value: postTitle, errorMessage: titleError } = useField('title');
       const { value: postBody, errorMessage: bodyError } = useField('body');

        //methods
        const submitPostForm = handleSubmit(() => {
         addPost({ title: postTitle, body: postBody });
        });

        return { schema, postTitle, postBody,  titleError, bodyError, submitPostForm };
    },
};
</script>

The problem that input error I have to show only in VFormGroup so how I can manage this form?


Solution

  • I am not sure if understood your question correctly. But in your case you only have 1 issue, you destructure errorMessage and value twice in one file, which isn't working.

    you could change your useField's like this:

    const { errorMessage: titleError, value: titleValue } = useField('title', Yup.string().required());
    const { errorMessage: bodyError, value: bodyValue } = useField('body', Yup.string().required().min(8));
    

    In your template you then want to use titleError and bodyError in your VFormGroup. In your VInput you want to use titleValue and bodyValue for v-model

    because you initialise your title and body in your setup() I guess that those do not have any predefiend values. If that would be the case you might want to take a look at the Options for useField() where you can have as a thridParam as an Object with e.g. initialValue as key which then would be your post.value.title. But for your use case I wouldn't recommend this.

    to answer the Code question from the comments:

    <template>
     <form class="shadow-lg p-3 mb-5 bg-white rounded" @submit="handleSubmit">
            <VFormGroup label="Title" :error="titleError">
                <VInput v-model="titleValue" type="text" name="title" />
            </VFormGroup>
            <VFormGroup label="Body" :error="bodyError">
                <VInput v-model="bodyValue" type="text" name="body" />
            </VFormGroup>
            <button type="submit" class="btn btn-primary">Submit</button>
        </form>
    </template>
    
    <script>
    import { ref } from 'vue';
    import { Form, useForm, useField } from 'vee-validate';
    import * as Yup from 'yup';
    
    export default {
        components: { Form },
        setup() {    
            const title = ref('');
            const body = ref('');
    
           //hooks
           const { handleSubmit } = useForm();
    
           // No need to define rules for fields because of schema
           const { errorMessage: titleError, value: titleValue } = useField('title', Yup.string().required());
           const { errorMessage: bodyError, value: bodyValue } = useField('body', Yup.string().required().min(8));
    
            return { titleError, bodyError, titleValue, bodyValue, handleSubmit };
        },
    };
    </script>