VueJS에서 form의 입력값의 유효성을 검증하는 방법에 대하여 알아보자.
library는 VeeValidate를 사용한다.
VeeValidate는 기존의 데이터입력 => rules.js 생성 => rule 생성 => validation => error, success, warning 을 모두 한번에 처리할 수 있다.
Setup
npm i vee-validate@next --save
or
yarn add vee-validate@next
Vue3 에서 VeeValidate를 사용할 수 있는 방법으로는 2가지가 있다.
Field Component |
Composition API |
Simplest approach |
More control |
Hard to customize / Only simple UI components |
Intuitive API |
|
Easy to use custom components |
기본적인 사용법
import {useField,useForm} from 'vee-validate';
export default {
setup(){
function onSubmit(){
alert('submit');
}
const validations = {
email: value => {
if(!value) return 'This field is required'; //error message
const regex = /.../;
if(!regex.test(String(value).toLowerCase())){
return 'Please enter a valid email address';
}
return true;
},
password: value => {
if(!value) return 'This field is required'; //error message
return true;
}
}
useForm({
validationSchemal: validations
})
const email = useField('email');
const password = useField('password');
// useField만 사용할때
// const email = useField('email',function(value){ // true 면 value 반환, false면 errorMessage 반환
// if(!value) return 'This field is required'; //error message
//
// const regex = /.../;
// if(!regex.test(String(value).toLowerCase())){
// return 'Please enter a valid email address';
// }
//
// return true;
// })
return{
onSubmit,
email: email.value,
emailError: email.errorMessage,
password: password.value,
passwordError: password.errorMessage,
}
}
}
- useField: single field validation
- useForm: validating at form level
Advanced 사용법
<template>
<div>
<BaseCheckbox
label="Catering"
v-model="catering"
:error="cateringError"
/>
...
</div>
<template>
<script>
import {useField, useForm} from 'vee-validate'
export default{
setup(){
const required = value => {
const requiredMessage = 'This field is required';
if(value === undefined || value===null) return requiredMessage;
if(!String(value).length) return requiredMessage;
return true;
}
const minLength = (number,value)=>{
if(String(value).length < number ) return 'Please type at leat ' + number;
}
const anything = ()=> true;
const validationSchema = {
category:required,
title: value => {
const req = required(value);
if(req!==true) return req;
const min = minLength(3,value);
if(min!==true) return min;
return true;
},
description: required,
location: undefined, // anything과 같은 효과
pets: anything,
catering: anything,
music: anything
}
useForm({
validationSchema
});
const {value: category, errorMessage: categoryError} = useField('category');
const {value: title, errorMessage: titleError} = useField('title');
const {value: description, errorMessage: descriptionError} = useField('description');
const {value: location, errorMessage: descriptionError} = useField('location');
const {value: pets, errorMessage: petsError} = useField('pets',undefined,{initialValue:1});
const {value: catering, errorMessage: cateringError} = useField('catering',undefined, {initialValue:false});
const {value: music, errorMessage: musicError} = useField('music',undefined,{initialValue:false});
return{
category,
cateoryError,
title,
titleError,
description,
descriptionError,
location,
locationError,
pets,
petsError,
catering,
cateringError,
music,
musicError,
}
}
}
</script>
위의 validation은 개별적으로 erorrMessage는 보여주지만 submit을 막지는 못한다.
=> 하나의 field라도 에러가 있다면 막아주는 함수가 바로 handleSubmit이다. 사용법은 다음과 같다.
또한 작업또한 굉장히 반복적이고 변수선언도 너무 많아진다.
=> useForm의 기능 (errors, initialValues) 로 해결할 수 있다.
<template>
<form @submit="submit">
<h1> Create an Event </h1>
<BaseSelect
label="Select a category"
:options="categories"
v-model="category"
:error="errors.category"
/>
...
</form>
</template>
<script>
import {useField, useForm} from 'vee-validate'
export default{
setup(){
...
const {handleSubmit, errors} = useForm({
validationSchema,
initialValues:{
pets:1,
catering:false,
music:false
}
});
const {value: category} = useField('category');
const {value: title} = useField('title');
const {value: description} = useField('description');
const {value: location} = useField('location');
const {value: pets} = useField('pets');
const {value: catering} = useField('catering');
const {value: music} = useField('music');
const submit = handleSubmit(values=>{
console.log('submit',values);
})
return{
..., // 개별적인 errorMessage는 모두 삭제
submit,
errors,
}
}
}
</script>
yup
validation rule을 생성하는것도 굉장히 귀찮은 일중에 하나이다. 이를 해결해 줄수 있는 라이브러리가 yup이다.
npm install yup
import {useField, useForm} from 'vee-validate';
import * as yup from 'yup';
export default{
setup(){
const validationSchema = {
category: yup.string().required(),
title:yup.string().required('A cool title is required').min(3),
description:yup.string().required(),
location:yup.string(),
pets: yup.number(),
catering: yup.boolean(),
music: yup.boolean(),
}
const {handleSubmit, errors} = useForm({
validationSchema,
initialValues:{
pets:1,
catering:false,
music:false
}
});
const {value: category} = useField('category');
const {value: title} = useField('title');
const {value: description} = useField('description');
const {value: location} = useField('location');
const {value: pets} = useField('pets');
const {value: catering} = useField('catering');
const {value: music} = useField('music');
const submit = handleSubmit(values=>{
console.log('submit',values);
})
return{
..., // 개별적인 errorMessage는 모두 삭제
submit,
errors,
}
}
}
Lazy Validation
input 이 focus를 잃은 후 입력값의 validation을 체크하는 것이 옳다. 이를 위해 validation은 change event에 trigger 되어야한다.
<template>
<BaseInput
label="Email"
type="email"
:error="emailError"
:modelValue="email"
@change="handleChange"
>
</template>
<script>
setup(){
...
const {setFieldValue} = useForm({
validationSchema: validations
})
const {value:Email, errorMessage:emailError} = useField('email');
const handleChange = (event) =>{
setFieldValue('email',event.target.value);
}
return{
onSubmit,
email,
emailError,
handleChange
}
}
</script>