While this tutorial has content that we believe is of great benefit to our community, we have not yet tested or edited it to ensure you have an error-free learning experience. It's on our list, and we're working on it! You can help us out by using the "report an issue" button at the bottom of the tutorial.

Introduction

Almost every web application makes use of forms in some way, as such developers always have to tackle form validations. If you are a new developer, it can be hard deciding how best to approach this. Depending on the stack you are using, there are many of options to choose from.

In this tutorial we will learn how to you can implement form validation in your form with Vue.

We want to show the error message as soon as the user hits the submit button—no need to send a response to the server—as the validation is on the client-side. Having a client-side validation does not remove the need of validating requests on your server—that is very important too.

Building the First Example

With that established, let’s build our form. First, our App component will only render the Register component:

<div id="app">
  <div>
    <Register />
  </div>
</div>

The script section will look like this:

new Vue({
  el: "#app"
})

For the Register component we want to show a form with inputs fields:

  <div>
    <h2>Register</h2>

    <form @submit.prevent="register" method="post">
      <div>
        <label>Name:</label>
        <input type="text" v-model="user.name" />
        <div>{{ errors.name }}</div>
      </div>
      <div>
        <label>Phone:</label>
        <input type="text" v-model="user.phone" />
        <div>{{ errors.phone }}</div>
      </div>
      <div>
        <label>Email:</label>
        <input type="text" v-model="user.email" />
        <div>{{ errors.email }}</div>
      </div>
      <div>
        <label>Password:</label>
        <input type="password" v-model="user.password" />
        <div>{{ errors.password }}</div>
      </div>
      <div>
        <button type="submit">Submit</button>
      </div>
    </form>
  </div>

The .prevent method is used to stop the default behavior of the form when a submission is made. The form has four inputs field for name, email, phone, and password. All of these will need their own validations. If there is an error with any of the inputs, it will be displayed below the input field.

Since each field is unique, we need to ensure the validation is suited to match their uniqueness. A general one is that none of the fields should be empty. We can check for this using !field.length, where field will equate to any of the input fields we have. To keep our code clean, the validators will be defined outside the Vue instance. If you are building this in an app that is scaffolded using Vue CLI, it means you’ll have the validators in a separate file.

const validateName = name => {
  if (!name.length) {
    return { valid: false, error: "This field is required" };
  }
  return { valid: true, error: null };
};

const validatePhone = phone => {
  if (!phone.length) {
    return { valid: false, error: 'This field is required.' };
  }

  if (!phone.match(/^[+][(]?[0-9]{1,3}[)]?[-\s.]?[0-9]{3}[-\s.]?[0-9]{4,7}$/gm)) {
    return { valid: false, error: 'Please, enter a valid international phone number.' };
  }

  return { valid: true, error: null };
}

const validateEmail = email => {
  if (!email.length) {
    return { valid: false, error: "This field is required" };
  }
  if (!email.match(/^\w+([.-]?\w+)_@\w+(_[_.-]?\w+)_(.\w{2,3})+$/)) {
    return { valid: false, error: "Please, enter a valid email." };
  }
  return { valid: true, error: null };
};

const validatePassword = password => {
  if (!password.length) {
    return { valid: false, error: "This field is required" };
  }
  if (password.length < 7) {
    return { valid: false, error: "Password is too short" };
  }
  return { valid: true, error: null };
};

For unique fields like email and phone number, we make use of regex to make sure it matches a specific pattern.
Each validator is a function that will receive the input field as a parameter. As you can see from above, each function returns valid and error. This is what we will use to determine if a form should be submitted. To see that in action, here is how the Register component will look:

Vue.component('register', {
  template: '#register',
  data() {
    return {
      user: {
        email: '',
        password: '',
        name: '',
        phone: ''
      },
      valid: true,
      success: false,
      errors: {},
      message: null
    }
  },
  methods: {

    register() {
      this.errors = {}

      const validName = validateName(this.user.name);
      this.errors.name = validName.error;
      if (this.valid) {
        this.valid = validName.valid
      }

      const validPhone = validatePhone(this.user.phone);
      this.errors.phone = validPhone.error;
      if (this.valid) {
        this.valid = validPhone.valid
      }

      const validEmail = validateEmail(this.user.email);
      this.errors.email = validEmail.error;
      if (this.valid) {
        this.valid = validEmail.valid
      }

      const validPassword = validatePassword(this.user.password)
      this.errors.password = validPassword.error
      if (this.valid) {
        this.valid = validPassword.valid
      }

      if (this.valid) {
        alert('HURRAAYYY!! :-)\n\n' + JSON.stringify(this.user))
      }
    }
  }
})

If a validator returns an error for any of the fields, the error returned is saved in the errors.fieldName—where fieldName is the name of the input field, and then displayed for the user to see what went wrong.

When all fields return valid as true, we can then go ahead to submit the form. For this tutorial, we are displaying an alert box.

Using Joi

Joi allows you to build schemas for JavaScript objects, which can be used to validate inputs. It is often used when working with Express and Restify. We can use it in this tutorial by defining a schema for our Register component.

Here is the schema:

import Joi from "joi";

const phoneRegex = /^[+]?[(]?[0-9]{3}[)]?[-\s.]?[0-9]{3}[-\s.]?[0-9]{4,7}$/gm;
const phone = Joi.string().regex(phoneRegex)
  .options({
    language: {
      string: {
        regex: {
          base: 'must be a valid phone number'
        }
      }
    }
  });

const userValidation = {};
userValidation.create = {
  first_name: Joi.string().min(2).max(24).required(),
  email: Joi.string().email().required(),
  password: Joi.string().min(7).required(),
  phone: phone.required()
};

We can then use the schema in our Register component to validate the inputs of the user:

Vue.component('register', {
  template: '#register',
  data() {
    return {
      user: {
        name: '',
        email: '',
        password: '',
        phone: ''
      },
      valid: false,
      success: false,
      errors: {},
      issues: {}
    }
  },
  methods: {
    // method that validates the user input using the schema
    validate(value, schema) {
      const result = Joi.validate(value, schema, { abortEarly: false });
      if (result.error) {
        result.error.details.forEach((error) => {
          this.issues[error.path[0]] = error.message;
        });
        return false;
      }
      return true;
    },

    register() {
      // validation method is called and passed the inputs and schema
      this.validate(this.user, userValidation.create);
        if (Object.keys(this.issues).length > 0) {
          this.errors = this.issues;
          return false;
        }
        alert('HURRAAYYY!! :-)\n\n' + JSON.stringify(this.user))
    }
  }
})

We declare a validate method that will accept the user inputs and the schema we have defined. If errors are found after the validation we will return a false and the errors encountered. If there are no errors, we display the alert box as we did before.

Conclusion

VeeValidate and Vuelidate are alternatives you can also make use of when handling form validation in your Vue application.

0 Comments

Creative Commons License