Vue3 Validation 플러그인 적용하기(VeeValidate + yup + i18n)_2

2024. 1. 15. 17:04뷰(Vue)

반응형

2024.01.15 - [뷰(Vue)] - Vue3 Validation 플러그인 적용하기(VeeValidate + yup + i18n)_1

 

Vue3 Validation 플러그인 적용하기(VeeValidate + yup + i18n)_1

Vue3에서 검색이나 입력에 대한 검증을 하나씩 하기보다는 공통적으로 적용되는 부분이 있었으면해서 찾아보았다. VeeValidate, Yup, Zod등이 있다. VeeValidate에서 자체적으로 Yup, Zod 등의 라이브러리와

lollaziest.tistory.com

 

이전에 작성한 1탄에 이어 2탄의 경우 VeeValidate와 yup 그리고 i18n모두 각각 언어설정이 필요한데 어떤식으로 적용했는지에 대해서 간략하게 정리를 해 두려고 한다.

여러가지 개념에 대한 정리.

Vee-validation에서도 제공하는 i18n이 있고 자체적으로 다국어를 위해 내가 적용시킨 vue-i18n이 있다.

그리고 yup이 있다.

Vee validation은 검증의 주체이다.

yup은 검증을 도와주는 도구.

Vee validation 만으로도 검증을 수행 할 수 있지만 몇몇 특이케이스를 빼고는 yup에서 지원하는것으로도 많은걸 커버 할 수 있다.

기본개념

useField로 명명된 필드값에 대해서 검증을 수행한다.

import { useField } from 'vee-validate';
//path, roles, opts 순서인데 syncVModel의 경우 vmodel로연결된 값을 연결할때 사용한다.
useField(() => props.field, undefined, { syncVModel: true });

실제로 검증하는 부분

//validation
import { useForm } from 'vee-validate';
import * as yup from 'yup';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const searchInfoField = '검색';
const { handleSubmit } = useForm({
    validationSchema: yup.object({
        searchInfo: yup
            .string(() => t('validation.string', { field: searchInfoField }))
            .max(5, ({ max }) => t('validation.max', { field: searchInfoField, length: max })), //임시조건
    }),
});

검증을 통과해야지만 실행되는 부분

/**
 * 조회
 * @returns {Promise<void>}
 */
const handleSearch = handleSubmit(async (values) => {
		// values검증의 대상 값이 들어온다.
    // validation 조건에 부합하지 않는경우 실행 안됨.
});

실제로 검증하는 부분에서 searchInfo로 명명되어있는데 해당값을 props로 전달하여

field="searchInfo"

path값에 연결된다. (props.field 부분)

만약 해당 컴퍼넌트를 그냥 명명한다면? 다르게 사용해야한다.

그냥 연결하고싶다면 간단한 예시는 다음과 같다.

validateOnInput 값을주면 input이 일어날때마다 검증하고. false라면 포커스가 사라져야지 검증을 수행한다.

<script setup>
import { useForm } from 'vee-validate';
import * as yup from 'yup';

const { values, errors, defineInputBinds } = useForm({
  validationSchema: yup.object({
    email: yup.string().email().required(),
  }),
});

const email = defineInputBinds('email', {
  validateOnInput: true,
});
</script>

<template>
  <input v-bind="email" />

  <pre>values: {{ values }}</pre>
  <pre>errors: {{ errors }}</pre>
</template>

컴포넌트화 시킨 대상일 경우 defineComponentBinds를 사용해서 연결한다.

참고주소

Getting started

 

Getting started

Field-level and form-level validation and validation behavior and error messages with composition API

vee-validate.logaretm.com

 

 

프로젝트에 적용시작

 

일단 대상은 심플하게 단어를 검색하는 searchbox가 있고 검색시 조건에 맞지않다면 특정 UI를 띄워주기 위해 Notice하는 ToastAlert을 담당하는 vue를 생성하였다.
그리고 매칭되는 값들의 경우 각각 VeeValidate에서 전달되는 값이다.

NoticeToast.vue

<template>
    <div>
        <template v-if="meta.valid">
            <div></div>
        </template>
        <template v-else-if="!meta.touched">
            <div></div>
        </template>
        <template v-else>
            <div class="notify show notify-field">
                <div v-for="error in errors">{{ error }}</div>
            </div>
        </template>
    </div>
</template>
<script setup>
// valid: The form’s validity status, will be true if the errors array is empty. After the form is mounted, vee-validate will update the flag to its accurate state
// touched: If at least one field was blurred (unfocused) inside the form.
// dirty: If at least one field’s value was updated.
// pending: If at least one field’s validation is still pending.
// initialValues: All fields’ initial values, packed into an object where the keys are the field names.
let props = defineProps({
    meta: { Type: Object, required: true },
    errors: { Type: Array, required: true },
});
</script>

 

ValidationSearchBox.vue 코드

<template>
    <div class="field p-fluid">
        <label>{{ label }}</label>
        <div class="p-input-icon-right p_notify">
            <i class="pi pi-search" />
            <InputText
                :id="field"
                :type="type"
                v-model="value"
                :placeholder="placeholder"
                @keyup.enter="handleEnter"
            ></InputText>
            <NoticeToast :meta="meta" :errors="errors"></NoticeToast>
        </div>
    </div>
</template>
<script setup>
import NoticeToast from '@/components/common/validation/NoticeToast.vue';

/**
 * label = 설명 라벨
 * placeholder =  검색창에 입력 없을 때 보여 지는 값
 * field =  validation으로 연결되는 필드명.
 */
let props = defineProps({
    label: { Type: String, default: '' },
    placeholder: { Type: String, default: 'Search' },
    field: { Type: String },
    type: { Type: String, default: 'text' },
});
let emits = defineEmits(['enter']);
function handleEnter() {
    emits('enter');
}
import { useField } from 'vee-validate';
import { watch } from 'vue';

//기본설정 rules, v-model 연동 true
const { value, errors, meta } = useField(() => props.field, undefined);
watch(value, (newValue, oldValue) => {
    emits('update:modelValue', newValue);
});
</script>

<style></style>

 

실질적으로 간단하게 설명하자면 props로 전달되는 field값을 사용하여 검증을 수행하는데..
여기서는 연결해주는 역할만 한다.

실질적으로 사용하는 부분의 코드

<template>
    <div class="field col-12 md:col-3">
        <ValidationSearchBox
            label="검색"
            field="searchInfo"
            v-model="search"
            placeholder="사용자,사용자명"
            @enter="handleSearch"
        ></ValidationSearchBox>
    </div>
</template>


<script setup>
import { ref } from 'vue';
let search = ref();

//validation
import { useForm } from 'vee-validate';
import * as yup from 'yup';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const searchInfoField = '검색';
const { handleSubmit } = useForm({
    validationSchema: yup.object({
        searchInfo: yup
            .string(() => t('validation.string', { field: searchInfoField }))
            .max(5, ({ max }) => t('validation.max', { field: searchInfoField, length: max })), //임시조건
    }),
});


/**
 * 조회
 * @returns {Promise<void>}
 */
const handleSearch = handleSubmit(async (values, actions) => {
    // validation 조건에 부합하지 않는경우 실행 안됨.
    common.toast.infoToast('조회');
    fetchListPage();
});
</script>

위와같이 사용한 이유는 여러가지가 있었지만 간단하게 설명하자면....
현재 검증과 다국어를 합쳐서 묶여있는 플러그인이 총3개이다.

VeeValidate
Yup
I18n

그런데 위 3개 모두 각각 자기들의 언어기준을 가지고있다.

I18n의 경우 이전에 ko,en을 세팅함.

근데 Yup, VeeValidate의 경우에도 여러가지 언어를 지원하지만 그 대상을 초기에 불러올때 지정하거나 동적으로 변환할때 적용시켜주는 로직을 작성해야함.

3개의 언어선택을 모두 동기화 시켜주거나 세팅을 해줘야하는 문제가 발생하는 것 같았다.

그래서 결국 i18n의 언어 선택값에 yup을 동기화 하고 그 검증값을 보여주는 형태로 적용시켰다..

 

실질적으로 동작하는 모습 예시

검증없을때

 

한글로 검증 값 표출

영어를 선택하고 검증 값을 동일하게 할때

 

결국은 i18n의 값을 가지고 다른 플러그인에 세팅되는 게 없이 동작하는 형태로 일단 사용해 보고 추가적으로 변경사항이 있는 경우에는 소스를 조금씩 바꿔가는 형태로 할 것 같다....!

 

반응형