Child Component Validation using Vuelidate

In this post, we will attempt to validate a form, which contains Child Components while submitting. This is a common scenario that one might face in real life. In this example, we will use the Vuelidate Library for validation.

Let us first define the Parent Component.

<template>
  <form @submit.prevent="onManualSubmit">
    <label for="name">Name</label>
    <input id="name" type="text" v-model="name" />

    <label for="caption">Caption</label>
    <input id="caption" type="text" v-model="caption" />

    <label for="description">Description</label>
    <ChildComponent v-model="description" />

    <button>Click</button>
  </form>
</template>

<script>
import ChildComponent from "./ChildComponent.vue";
export default {
  name: "HelloWorld",
  components: { ChildComponent },
  data() {
    return {
      name: "",
      caption: "",
      description: "",
    };
  },
  methods: {
    async onManualSubmit() {
        // Submit form
    },
  },
};
</script>

<!-- Add"scoped" attribute to limit CSS to this component only -->
<style scoped>

</style>

As you can observe in the code above, our Parent Form contains 2 fields and an additional Child Component. The parent component accepts a namecaption and description values. The description is fetched from the ChildComponent. Let us define the ChildComponent now.

<template>
  <input type="text" v-model="modeValue" />
</template>

<script>
export default {
  name: "ChildComponent",
  props: {
    modelValue: String,
  },
  
};
</script><style scoped>
</style>

The ChildComponent has a single prop, which is bound to the input. This is the field, which would accept the description model from the Parent.

Validation

Now, let us add the validation. As mentioned earlier, we are using the Vuelidate library for the purpose in this example. Let us go ahead and it to the project.

npm install @vuelidate/core @vuelidate/validators

We will begin in the ChildComponent now and add vuelidate to it.

<script>
import useVuelidate from"@vuelidate/core";
import { required } from"@vuelidate/validators";
exportdefault {
  name: "ChildComponent",
  setup() {
    return {
      v$: useVuelidate(),
    };
  },
  props: {
    modelValue: String,
  },
  validations() {
    return {
      modelValue: { required },
    };
  },
};
</script>

We have first imported the useVuelidate from the @vuelidate/core library. Vuelidate has a few inbuild validators and in this example we would be using one of them – required. Note that we can define custom validators, however, that is out of scope of this article. We will address it one of the future posts.

We will first define the validations, which we would be required by our models. In this case, we have a single model, which needs to be validation – modelValue.

validations() {
    return {
      modelValue: { required },
    };
  },


As seen in the code above, we have defined a function validations(), which would return an object with property with same name as our model modelValue. We have also specified that the modelValue should use the required attribute.

The next step is to ensure our component utilizes the validations we have defined. We activate vuelidate by calling useVuelidate() inside the setup(), which would internally use the rules returned by the validations() to validate the form. We also need a way to indicate the error back to the user, when the form is validated. For that, we will add UI elements, which would display the information to the user.

<input type="text" v-model="modeValue" /><p v-if="v$.modelValue.$error"><span v-if="v$.modelValue.required" class="error"
    >Description is a Required field.</span
>
</p>

Once the form is validated, the v$ object would contain the validation errors we have in the form. This can be used to display the error back to the user.

The complete ChildComponent is shown below.

<template>
  <input type="text" v-model="modeValue" /><p v-if="v$.modelValue.$error">
    <span v-if="v$.modelValue.required" class="error"
      >Description is a Required field.</span
    >
  </p>
</template><script>
import useVuelidate from "@vuelidate/core";
import { required } from "@vuelidate/validators";
export default {
  name: "ChildComponent",
  setup() {
    return {
      v$: useVuelidate(),
    };
  },
  props: {
    modelValue: String,
  },
  validations() {
    return {
      modelValue: { required },
    };
  },
};
</script><style scoped>
</style>

Similarly, we can add validation to the Parent Form.

<template>
  <form @submit.prevent="onManualSubmit">
    <label for="name">Name</label>
    <input id="name" type="text" v-model="name" />
    <p v-if="v$.name.$error">
      <span v-if="v$.name.required" class="error"
        >Name is a Required field.</span
      >
    </p>

    <label for="caption">Caption</label>
    <input id="caption" type="text" v-model="caption" />
    <p v-if="v$.caption.$error">
      <span v-if="v$.caption.required" class="error"
        >Caption is a Required field.</span
      >
    </p>

    <label for="description">Description</label>
    <ChildComponent v-model="description" />

    <button>Click</button>
  </form>
</template>

<script>
import useVuelidate from "@vuelidate/core";
import { required } from "@vuelidate/validators";
import ChildComponent from "./ChildComponent.vue";
export default {
  name: "HelloWorld",
  setup() {
    return {
      v$: useVuelidate(),
    };
  },
  components: { ChildComponent },
  data() {
    return {
      name: "",
      caption: "",
      description: "",
    };
  },
  validations() {
    return {
      name: { required },
      caption: { required },
      description: { required },
    };
  },
  methods: {
    async onManualSubmit() {
      var validationResult = await this.v$.$validate();

      if (!validationResult) {
        console.log("Validation failed");
        return;
      }

      // Validation Successful, can submit the form now.
      console.log("Validation successful");
      // submit();
    },
  },
};
</script>

<style scoped>

</style>


Notice that the code is quite similiar to the ChildComponent, except for the onManualSubmit method. In this method, which is used to submit the form, we first validate the form by calling the v$.$validate() method. This would validate all the validation objects within the form, including the ChildComponent.

That’s all we require for validating Child Components using Vuelidate.

Leave a comment