Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Validate child input components on submit with Vee-Validate

Tags:

vue.js

I'm currently trying to create a Registration form with multiple "Input Field" components which all require validating once Submit has been pressed. They all currently validate on their own accord when the text within is changed but I'm finding it difficult to make a global call to all input fields to validate all. What I am trying to achieve is the following: http://vee-validate.logaretm.com/examples#validate-form but the validateAll() method has no fields attached to it.

I tried populating validateAll() with email & confirm_email which got me the result I wanted, but the error messages would not show next to the fields.

Any help would be much appreciated!

ValidatedInputField.vue:

<template>
   <div class="form-control" v-bind:class="{ errorPrompt : errors.has(name) }">
      <label v-bind:for="name">* {{as}}</label>
      <input ref="input" v-bind:value="_value" @input="updateValue($event.target.value)" v-validate v-bind:data-vv-rules="rules" v-bind:name="name" />
      <span v-bind:v-show="'errors.has(' + name +')'">{{ errors.first(name) }}</span>
   </div>
</template>

<script>
module.exports = {
  props: ['name', 'rules', 'as', 'value'],
  methods: {
  updateValue(value) {
     this._value = this.value;
     this.$emit('input', value);
  }
  },
  computed: {
     _value() { return this.value; }
  }
};
</script>

Register.vue:

<template>
  <div class="container">
    <Card blueHeader="true" title="Register">
      <ValidatedInputField v-model="email" name="email" rules="required|email" as="Email" />
      <ValidatedInputField v-model="confirm_email" name="confirm_email" rules="required|email" as="Confirm Email" />
      <ValidatedInputField name="company" rules="required" as="Company" />
      <InputField name="company_website" as="Company Website" />
      <ValidatedInputField name="first_name" rules="required" as="First Name" />
      <ValidatedInputField name="last_name" rules="required" as="Last Name" />
      <ValidatedInputField name="address_1" rules="required" as="Address 1" />
      <InputField name="address_2" as="Address 2" />
      <ValidatedInputField name="city" rules="required" as="City" />
      <ValidatedInputField name="zip" rules="required" as="Zip/Postal Code" />
    </Card>

    <Card blueHeader="true" title="Terms & Conditions">
      <button v-on:click="submitForm()">Submit</button>
    </Card>
  </div>
</template>

<script>
import ValidatedInputField from './components/ValidatedInputField';
import InputField from './components/InputField';

module.exports = {
  methods: {
    submitForm() {
      this.$validator.validateAll();
    }
  },
  data() {
    return {
      email: '',
      confirm_email: ''
    };
  },
  components: {
    ValidatedInputField,
    InputField
  }
};
</script>
like image 832
ChalkyJoe Avatar asked Dec 07 '16 16:12

ChalkyJoe


3 Answers

I have a similar setup, I tried the bus solution with the events, didn't get it working. I however used the Provider/Injector pattern as defined in the specs of v-validate.

So in the top most parent, add this line of code (mind it is TYPESCRIPT !)

 @Provide('validator') $validator = this.$validator;

And in every child/grandchilds add this line of code:

@Inject('validator') $validator: any;

Now you can do this in your parent, and I will gather all errors from all components with the validator injector. (see specs: https://baianat.github.io/vee-validate/api/errorbag.html#api)

 if (this.$validator.errors.any()) {
      // Prevent the form from submitting
      e.preventDefault();
    }

I have a sort-a-like answer in post; vee-validate error object - _vm.errors is undefined

grtz

like image 154
Ben Croughs Avatar answered Sep 28 '22 03:09

Ben Croughs


For plain Vuejs i use:

inject: ['$validator'],

in the child,

and:

provide() {
   return {
     $validator: this.$validator,
   };
},

in the parent.

like image 38
PulpDood Avatar answered Sep 28 '22 03:09

PulpDood


In my case what I do is that I that I disable vee-validate injection:

Vue.use(VeeValidate, { inject: false });

This will make the plugin stop instantiating a new validator scope for each component instance, excluding the root instance.

And in the parent component i get a new validator instance which i'll share with the desired childs:

export default {
  $_veeValidate: {
      validator: 'new' // Determines how the component get its validator instance
                       // 'new' means it will always instantiate its own validator instance
  },
  ......

In the child component i inject that parent's validator instance:

export default {
    // This will make the component inherit it's parent's validator scope,
    // thus sharing all errors and validation state. Meaning it has access
    // to the same errors and fields computed properties as well.
    inject: ['$validator'],
    ...........

Resource: https://baianat.github.io/vee-validate/concepts/components.html

like image 30
Abouhassane Abdelhamid Avatar answered Sep 28 '22 03:09

Abouhassane Abdelhamid