Skip to content

How to use

Erik Isidore edited this page May 17, 2019 · 3 revisions

How to use

vue-convenia-validator is a model-based, template-independent validation library, which means that it is completely decoupled from how you build your templates.

Instead, it takes the input values of your form directly from the data of your component and validates it according to the validation rules you defined for each field in your component.

This little guide will provide in-depth explanation of all the ways you can use the validator you've been warned.

Using the mixin

In order to use the validator, first you'll need to import the FormValidator mixin and use it on the component you wish to have form validation:

<template>
  <div id="vue-app">
    <form>
      <input name="fullName" type="text" v-model="fullName" />
      <input name="birthday" type="text" v-model="birthday" />
    </form>
  </div>
<template>

<script>
import FormValidator from 'vue-convenia-validator'

export default {
  mixins: [ FormValidator ],

  data () {
    return {
      fullName: '',
      birthday: ''
    }
  }
}
<script>

Initializing the validator

There are two ways you can initialize the validator in your component:

  • You can defined a validations object in the root level of your component, we'll go into the structure of this object in a bit.

  • You can simply use $this.validator.init(<ValidationsObj>) whenever you want anywhere in your app

Defining validation rules

For those that are familiar with TypeScript, the object containing your form(s) field validations that you have to pass to the validator is defined as follows:

export type FieldValidation = string | Array<string> | { [rule: string]: any }

export type FormValidation = { [fieldName: string]: FieldValidation }

export type ScopedFormValidation = { [scope: string]: FormValidation }

export type FormTemplate = ScopedFormValidation | FormValidation

Ultimately, the object that the validator receives from your componente has to follow the FormTemplate signature. Now, for those that aren't familiar with TypeScript, what this means is (bear with me):

First of all, the structure of this object basically matches the structure of the data in your component, where you have the actual values for each field in your form. So in practice, this means that if I have my data structured in this manner:

data () => ({
  fieldOne: '',
  fieldTwo: 'potato'
})

The validation object would look like this:

validations: {
  fieldOne: 'required',
  fieldTwo: 'alphanumeric'
}

But if it looks like this:

data () => ({
  formOne: {
    fieldOne: '',
    fieldTwo: 'potato'
  }
})

My validation object must look like this:

validations: {
  formOne: {
    fieldOne: 'required',
    fieldTwo: 'alphanumeric'
  }
}

By the way, this thing we used in the last example is called a scope, scopes allow us to use the validator with multiple formularies on the same componente, avoiding conflict with field names and form validation states etc. Basically I can have formOne.fieldOne and formTwo.fieldOne, on the same componente and these two formularies will be validated separately (you can't have two scopes with the same name of course).

That's basically what the type signature of FormTemplate means, you can either have an object with scopes (e.g. { formOne: { field: '', ... }, formTwo: { field: '' , ... }, ... }), or an object with the rules of each field directly, but it has to match the structure of the data in your component.

Field rules

In the previous section I've shown four TypeScript types, the section also explains what the last two means, now onto the first two:

export type FieldValidation = string | Array<string> | { [rule: string]: any }

export type FormValidation = { [fieldName: string]: FieldValidation }

Basically what this means is that, the rule that you'll defined for each field can either be a string, an array of strings, or an object (it's not very clear in the type, but it can also be a function that returns one of these three):

validations: {
  fieldOne: 'required',
  fieldTwo: ['required', 'dateFormat'],
  fieldThree: { regex: '/\D{5}/', },
  fieldFour: (formData) => ({ custom: () => formData.fieldOne === 'bla' })
}

Now let's go through each of these four possibilities and what they mean:

  1. String: When the value of the validation is simply a string, you're just passing the name of the rule you want to apply to this field.

  2. Array: An array of string is basically an array of rules you want to apply to a certain field, you use this form when you just wanna use more than one rule on a given field.

  3. Object<{ [ruleName]: any }>: Now, when you pass an object as the validation for a field, it acts similarly to an array, you can use more than one rule for a given field, but not only that: some rules also accept arguments, normally you can pass arguments to a rule even in string format (e.g. fieldName: '<ruleName>:<arguments>', that would look like: dateFormat:YYYY-MM-DD) but when you pass an object you can use even more complex arguments. Some rules even accept functions as arguments, but we'll go into these more advanced uses later on.

  4. Function <(formData, validations) => FieldValidation>: You use functions for your field validations when you need more complex logic. This function must return one of these three last options, it will basically return the actual validation rule, either an string, array of strings of object. The difference here is that the function allows you to have access to the state of the form and the validation state of each field (we'll go into that later), so you can dinamically change the validation rules of a field according to the state of the form, among other things.

That's basically it for field rules, we'll go into much more detail about all the cool stuff you can do with them in a dedicated page about each rule and types of rules.

Scopes and template structure

It's important to note that each input field in your template must have a name property that corresponds to the variable name in the data. For example:

<template>
  <form>
    <input name="fieldOne" type="text">
  </form>
</template>

<script>

export default {
  data: () => ({
    fieldOne: ''
  })
}
</script>

And for each scope you have, each form in your template must also have a corresponding name property:

<template>
  <div>
    <form name="formOne">
      <input name="fieldOne" type="text">
    </form>

    <form name="formTwo">
      <input name="fieldOne" type="text">
    </form>
  </div>
</template>

<script>

export default {
  data: () => ({
    formOne: { fieldOne: '' },
    formTwo: { fieldOne: '' },
  })
}
</script>

Validation flags

Once you declare the validation rules for each of your fields, the validator will initialize these rules, look for the correspoding elements in the DOM, and trigger each the field validation whenever it changes.

At this point, the validation of your forms should be working, and you'll have a $validations computed object accessible from the componente where you registered the FormValidator mixin, this computed object contains the validation state for each field of each form you have registered for validation.

Assuming we have registered our field validations in our component like this:

export default {
  data: () => ({
    formOne: {
      fieldOne: '',
      fieldTwo: '',
    },
    formTwo: {
      fieldOne: "I'm filthy",
      fieldTwo: ''
    }
  }),

  validations: {
    formOne: {
      fieldOne: 'required',
      fieldTwo: 'dateFormat'
    },

    formTwo: {
      fieldOne: 'numeric',
      fieldTwo: 'pis'
    }
  },

  methods: {
    ...
  }
}

Our $validations computed object will look like this:

{
  formOne: {
    fieldOne: {
      pristine: true,
      dirty: false,
      changed: false,
      touched: false,
      valid: false,
      errors: []
    },
    fieldTwo: {
      pristine: true,
      dirty: false,
      changed: false,
      touched: false,
      valid: false,
      errors: []
    }
  },

  formTwo: {
    fieldOne: {
      pristine: false,
      dirty: true,
      changed: false,
      touched: false,
      valid: false,
      errors: []
    },
    fieldTwo: {
      pristine: true,
      dirty: false,
      changed: false,
      touched: false,
      valid: false,
      errors: []
    }
  }
}

For each field of each form, the validator will generate this flags and update them whenever the field's value changes. Heres what each of these flags mean:

{ pristine: 'True if the value of the field is empty, false otherwise.'
, dirty: 'True if the value of the field is not empty, false otherwise.'
, changed: 'True if the current value of the field is different from its initial value, false otherwise.'
, touched: 'Becomes True once the `blur` event triggers for the respective field element.'
, valid: 'True if all the validation rules applied to this field pass without errors, false otherwise.'
, errors: 'An array of error messages, each validation rule registered to this field that fails the, will add it"s default error message to this array.'
}

I think that's it for the basics (i know its a lot sorry), for even more in-depth information about the API, checkout our API Reference, for more information about each rule and how they work, see the Rules Reference.