🍙

Vuelidate 2の使い方

2022/02/26に公開

Vuelidate 2について

フォームデータのバリデーションを行うライブラリです。
執筆時のバージョンは2.0.0-alpha.26です。

公式サイト: https://vuelidate-next.netlify.app/

Vue 2.x系ではCompositionAPI必須です。
古いバージョンとは書き方が違うので注意してください。

セットアップ

こちらにサンプルのリポジトリを置きました。
https://github.com/naga3/vuelidate-example

自分で作る場合は以下のような感じです。

# yarn global add @vue/cli  # Vue CLIが入っていない場合
vue create vuelidate-example
cd vuelidate-example
yarn add @vuelidate/core @vuelidate/validators
yarn serve

Vue CLIのオプションは以下のようにしました。

Please pick a preset: Manually select features
Check the features needed for your project: Babel, TS, Linter
Choose a version of Vue.js that you want to start the project with 3.x
Use class-style component syntax? No
Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes
Pick a linter / formatter config: Basic
Pick additional lint features: Lint on save
Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files

VuelidateはComposition APIに適しているようなので、そちらを使用します。
https://vuelidate-next.netlify.app/advanced_usage.html#composition-api

最小限のサンプル

これだけで動きます。
https://github.com/naga3/vuelidate-example/blob/main/src/Minimum.vue

<template>
  <input v-model="v$.name.$model">
  {{ v$.name.$errors[0]?.$message }}
</template>

<script lang="ts">
import { ref } from "vue"
import useVuelidate from "@vuelidate/core"
import { required } from "@vuelidate/validators"

export default {
  name: "Minimum",
  setup() {
    const name = ref("")
    const rules = {
      name: { required }
    }
    const v$ = useVuelidate(rules, { name })
    return { v$ }
  }
}
</script>

バリデーションルールのキーとしてバリデーション対象の変数名をセットする感じです。

dirty状態について

Vuelidateにはdirty状態という概念があり、最初にこれを理解しておかないと後がツラいです。初期実行時など、フィールドが空っぽで開かれたときに、requiredバリデーションなどが働いてエラーメッセージが表示されてはいけないので、フィールドを「触る」まではditryではなくしておいて、バリデーションが動かないようにする仕組みです。

https://vuelidate-next.netlify.app/guide.html#the-dirty-state

バリデーションする各項目には $dirty, $error, $errors, $invalid プロパティが生えています。

  • $dirty: dirtyになるとtrue
  • $error: エラーがある場合はtrue。$dirty を考慮する
  • $errors: エラーメッセージの配列。$dirty を考慮する
  • $invalid: エラーがある場合はtrue。$dirty を考慮しない

dirty状態を制御するには3つの方法があり、以下にサンプルを置きました。
https://github.com/naga3/vuelidate-example/blob/main/src/Dirty.vue

Dirty

  1. 一番上のフィールドはデータをそのまま置いた場合。dirty状態が考慮されないのでエラーが表示されない。
  2. 二番目のフィールドは、フィールドに入ったときに $reset メソッドでdirty状態をクリアし、フィールドから抜けたときに $touch メソッドでdirtyにしています。dirty状態のタイミングを制御したい場合はこちらを使います。
  3. 三番目のフィールドは $model を使う場合。こちらはデータのプロキシとして働き、変更があったときにdirtyにしてくれます。
  4. 四番目のフィールドは $autoDirty を使う場合。こちらをセットしておくとデータが変更されたときにditryにするwatcherが内部的に作られます。

バリデーションのサンプル

フォームのsubmit

サンプルはこちら
https://github.com/naga3/vuelidate-example/blob/main/src/Submit.vue

Submit

すべてのフィールドのバリデーションを通したい場合に $validate メソッドを実行します。その際はすべてのフィールドがdirtyになります。

メールアドレスのバリデーション

メールアドレスを2回入力させて、同じ値である検証をやってみましょう。
以下の組み込みバリデータを使います。

有効なメールアドレス
https://vuelidate-next.netlify.app/validators.html#email

2つのフィールドに入力された値が同じかどうか
https://vuelidate-next.netlify.app/validators.html#sameas

サンプルはこちら。
https://github.com/naga3/vuelidate-example/blob/main/src/Email.vue

Email

検証用のフィールド(email2)を触っていない状態ではエラーが出なくなってしまうので、v$.value.email2.$touch() によって強制的にdirtyにしています。

カスタムメッセージ

デフォルトのエラーメッセージから変更したいときは以下のようにします。
https://vuelidate-next.netlify.app/custom_validators.html#custom-error-messages

サンプルはこちら。
https://github.com/naga3/vuelidate-example/blob/main/src/CustomMessage.vue

CustomMessage

下のフィールドの例では、バリデータのパラメータ(最小文字数が4)を参照して、メッセージに反映しています。

カスタムバリデータ

自前のバリデータを作成できます。ドキュメントはこちら。
https://vuelidate-next.netlify.app/custom_validators.html

サンプルはこちら。
https://github.com/naga3/vuelidate-example/blob/main/src/CustomValidator.vue

Mario Family

バリデーション対象の値を受け取って、Bool値を返す関数をカスタムバリデータとして使えます。

const isMario = (value: string) => value === "Mario"

パラメータ付きのカスタムバリデータは、バリデータを返す高階関数で実現できます。

const is = (param: string) =>(value: string) => value === param
// 例: is("Luigi")

他のフィールドも絡めたバリデータを作成する場合は、第2引数を使います。

const isFamily = (value: string, siblings: any) => {
  const mario = isMario(siblings.name1.value)
  const luigi = is("Luigi")(siblings.name2.value)
  return mario && luigi && value === "Peach"
}

Discussion