Movatterモバイル変換


[0]ホーム

URL:


Vijit Ail
Developer Mentoring

Form Validation in VueJS using Yup

Fri May 15 2020

Admit it, handling form validations is a pain when it comes to JavaScript frameworks. Although, form validation is available natively in the browser, there are still somegotchas when it comes to cross-browser compatibility. There are many validation libraries you might want to choose from, but don't know how to get started.

VueJS ecosystem has form validation libraries likevuelidate andVeeValidate. These libraries are great, but I would like to show you an alternative way of handling validations using a schema-based validation library calledyup.

Before getting started, note that this demo usesspectre.css framework for styling the form, but you can do the same with pretty much all the CSS frameworks.

Open up your favourite text editor and let's get started!

Initial Form

For this demo, we will be working with a Login Form. The form will have two fields; email and password. Each field will have itsv-model value. Use the@submit.prevent directive to prevent the default form submission behavior and call theloginUser() method.

<template><divid="app"><formclass="login-form"@submit.prevent="loginUser"><h2>Login</h2><divclass="form-group"><labelclass="form-label"for="email">Email</label><inputid="email"name="email"type="email"v-model="email"class="form-input"/></div><divclass="form-group"><labelclass="form-label"for="email">Password</label><inputid="password"name="password"type="password"v-model="password"class="form-input"/></div><buttonclass="btn btn-primary btn-block">Login</button></form></div></template>
exportdefault{name:"app",data(){return{email:"",password:"",};},methods:{loginUser(){      console.log("Logging In...");},},};

Installing and configuringyup

Yup is an Object schema based validation and parsing library. It can define a schema, validate the shape of an existing object, transform a value to match, or both. The feature I like the most about Yup is that it has a straightforward API which makes it very easy to use.

Now that you have the basic form set up; install yup using yarn or npm.

yarnadd yup

Either you can import the required stuff fromyup, or everything as shown below.

import{ object, string}from"yup";// to import everything from yupimport*as yupfrom"yup";

Creating the validation Schema

To define an object schema, use theobject() method and call theshape() method attached to it with your schema.

const loginFormSchema=object().shape({// schema});

Or you could just pass your schema in theobject() method.

const loginFormSchema=object({// schema});

Since you have string based validations, use thestring() method to define a string schema.

So for the email and password fields it will be,

{email:string().required().email(),password:string().required()}

So putting it all together, your final validation schema should look as follows.

const loginFormSchema=object().shape({email:string().required().email(),password:string().required(),});

You can add more validation methods likemax() andmin() on the password field, I'm leaving that up to you. You can check out all the other validation methods in the Yup repo.

Adding Validation

You need to trigger the validation when the user is typing in the field, or when the field loses focus. So use the@keypress and@blur event directives on the inputs and call thevalidate() method with the field name.

<inputid="email"name="email"type="email"v-model="values.email"class="form-input"@blur="validate('email')"@keypress="validate('email')"/><!-- --><inputid="password"name="password"type="password"v-model="values.password"class="form-input"@blur="validate('password')"@keypress="validate('password')"/>

Refactor thedata object to include the error messages as well.

exportdefault{name:"app",data(){return{values:{email:"",password:"",},errors:{email:"",password:"",},};},methods:{// ...},};

Now, let's define the validate method. The validate method, as the name suggests, will validate a single field against the validation schema. You can do that by using thevalidateAt() method of the validation schema.

ThevalidateAt() method returns aPromise, so you can catch all the validation errors in thecatch callback. If you console log theerr object, you will find the error message in themessage property.

// ...methods:{loginUser(){// ...},validate(field){      loginFormSchema.validateAt(field,this.values).catch(err=>{          console.log(err);/*            {              errors: ["email is a required field"],              inner: [],              message: "email is a required field",              name: "ValidationError",              params: {path: "email", value: "", originalValue: "", label: undefined},              path: "email",              type: "required",              value: "",              // ..            }          */});},}// ...

When the validation fails assign the error message to the property for that field in theerrors object. For example, if there's an error in the email field, assign the error message tothis.errors.email. You also need to clear the error message from theerrors object if there's no error.

// ...methods:{loginUser(){// ...},validate(field){      loginFormSchema.validateAt(field,this.values).then(()=>{this.errors[field]="";}).catch(err=>{this.errors[field]= err.message;});},}// ...

TheloginUser() method will be called when the user clicks on the submit button. Here, you need to validate both the fields using thevalidate() method. By default thevalidate() method will reject the promise as soon as it finds the error and wont validate any further fields. So to avoid that you need to pass theabortEarly option and set the boolean to false{ abortEarly: false }.

methods:{loginUser(){      loginFormSchema.validate(this.values,{abortEarly:false}).then(()=>{this.errors={};// login the user}).catch(err=>{          err.inner.forEach(error=>{this.errors[error.path]= error.message;});});},// ...}

Rendering errors on the form

Now that you are storing the error messages, let's see how you can render them in the form. This next part will depend on the CSS framework that you are using. Spectre uses thehas-error class to change the input's border color to show the error.

For the email field, you can check if there's any message in theerrors.email field and add thehas-error class.

<div:class="[ 'form-group', !!errors.email && 'has-error' ]"><!-- --></div>

And then you can render the message after the input as shown below.

<!-- After the input --><pclass="form-input-hint"v-if="!!errors.email">  {{ errors.email }}</p>

Similarly, you can do for the password field as well.

<div:class="[ 'form-group', !!errors.password && 'has-error' ]"><labelclass="form-label"for="password">Password</label><inputid="password"name="password"type="password"v-model="values.password"class="form-input"@blur="validate('password')"@keypress="validate('password')"/><pclass="form-input-hint"v-if="!!errors.password">    {{ errors.password }}</p></div>

Refactoring inputs

As you can see above, the input field has got a lot of templates that can be abstracted by creating it as a separate component. So, let's do that and pass the type, label, name, value and error as props.

exportdefault{name:"form-input",props:{type:{required:true},label:{required:true},name:{required:true},value:{required:true},error:{required:true},},};

To implement the v-model directive in a custom component, you need to specify the value prop and the input event in the input tag inside the custom component.

For more info, you can check out thisguide in the official VueJS site and further refactor the component, but for brevity purpose, I'm skipping that for now.

<template><div:class="[ 'form-group', !!error && 'has-error' ]"><labelclass="form-label"for="email">{{label}}</label><input:id="name":name="name":type="type":value="value"@input="$emit('input', $event.target.value)"class="form-input"@blur="$emit('validate')"@keypress="$emit('validate')"/><pclass="form-input-hint"v-if="!!error">{{ error }}</p></div></template>

After you are done with the custom input component, you can use it inside the form as shown below.

<form-inputlabel="Email"v-model="values.email"type="email"@validate="validate('email')"name="email":error="errors.email"></form-input>

You can find the entire code for this blog in thisrepo.

Conclusion

Well, that was simple right? Form validation on the frontend can be a pain, but Yup makes it super easy for us to handle custom form validations.

Now that validation is dealt with, in the next part I'll show you how to create a reusable and declarative form API to handle the form values and errors so that you don't have to repeat yourself again and again for each form in your application.

If you read this far, and liked the post, please support and share.

🤙 Get in touch with me

vijit2ail@gmail.com Check out my Github Designs on Dribbble Follow me on Medium
This site is built withGatsby and powered byNetlify

[8]ページ先頭

©2009-2025 Movatter.jp