【 Nuxt3 】VeeValidate + yup カスタム input コンポーネントでバリデーションを行う

2023年8月2日

前回こちらで yup を使ったバリデーションについての記事を上げましたが、今回はバリデーションの全体像についてです。input タグではなく自前のカスタムコンポーネントをプロジェクト内部で作る事はよくありそうですが、入力と双方向バインディングできるカスタムコンポーネントのバリデーション方法が説明されている記事が見当たらなかったので残しておきます。

バリデーション実装前

以下のような自前の text input があるとします。

<script setup lang="ts">
   type Props = {
    /** id属性 @type {string} */
    id: string;
    /** modelValue @type {string} */
    modelValue: string;
    /** name属性 @type {string} */
    name: string;
    /** disabled属性 @type {boolean} */
    disabled?: boolean;
  };

  const props = withDefaults(defineProps<Props>(), {
    disabled: false,
  });

 const emit = defineEmit<{
  (event:'update:modelValue', data:string): string;
 }>()

 const modelValue = computed({
  get: () => props.modelValue,
  set: (value) => { 
    emit('update:modelValue', value);
  },
});

</script>
<template>
  <div>
    <input
      :id="id"
      v-model="modelValue"
      type="text"
      :name="name"
      :disabled="disabled"
    />
  </div>
</template>

これを以下のような感じで呼び出すとします。

<template>       
  <MyTextInput
    id="test"
    name="test"
    v-model="text"
  />
</template>

App.vue で定義したリアクティブな変数 text の値が変わると MyTextInput の入力値も変わってくれるはずです。

こちらにバリデーションを追加していきます。

バリデーション実装後

以下のように vee-validate の useField を使用していきます。

<script setup lang="ts">
   import { useField } from 'vee-validate';

   type Props = {
    /** id属性 @type {string} */
    id: string;
    /** modelValue @type {string} */
    modelValue: string;
    /** name属性 @type {string} */
    name: string;
    /** disabled属性 @type {boolean} */
    disabled?: boolean;
  };

  const props = withDefaults(defineProps<Props>(), {
    disabled: false,
  });

  const { value } = useField(() => props.name, undefined, {
    syncVModel: true,
  });


</script>
<template>
  <div>
    <input
      :id="id"
      v-model="value"
      type="text"
      :name="name"
      :disabled="disabled"
    />
  </div>
</template>

useField の第三引数で指定されている syncVModel を true とすると元々 emit の update:modelValue で行なっていた値の更新をわざわざ定義しなくても useField 側で行なってくれるのと、以下、その値に対してバリデーションを行う事ができるようになります。

利用側では以下のように useForm が返す validate を用いてバリデーションを行います。

useForm には以下のように schema を定義できます。この部分は前回の記事で紹介しています。

以下 check 関数を呼べばバリデーションが動くという作りです。

<script setup lang="ts">
  import { useForm } from 'vee-validate';

  const text = ref<string>('')

  const schema = yup.object({
    test: yup.string().when({
      is: () => text.value,
      then: (schema) => schema.matches(/^[0-9a-zA-Z]+$/, '半角英数字で入力して下さい。'),
    }),
  });

  const { validate } = useForm({
    validateOnMount: false,
    validationSchema: schema,
  });

const check = async () => {
  const { result } = await validate()
  console.log(result)
}

</script>
<template>       
  <MyTextInput
    id="test"
    name="test"
    v-model="text"
  />
</template>

最後に

以上になります。カスタムインプットを作って PJ 内で共通で使うような場面は結構あるとは思うのと、Nuxt3 で バリデーションといえば最初に出てきそうなのが vee-validate なのでこの処理はよく使われそうなものですが調べてもあまり載っていなかったのは不思議です。ただ恐らくこんな感じで問題ないかと思います。

学習用書籍