VeeValidateを使ってVueアプリでバリデーションをする

# VeeValidate

VeeValidateは以下の特徴を備えたVue.jsのバリデーションライブラリーです。
ドキュメントを読みつつ訳しながらまとめた内容です。

https://logaretm.github.io/vee-validate/

- テンプレートベースのバリデーション
- 多彩なバリデーションルールがデフォルトで用意済み
- 一級のローカライゼーションサポート
- HTML5のinputフォームとカスタムコンポーネントのバリデーションが可能
- カスタムルールとエラーメッセージも作成可能

## はじめよう

### 利用方法

まずVueのインスタンスに登録します。

```js
import Vue from 'vue';
import VeeValidate from 'vee-validate';

Vue.use(VeeValidate);
```

コンフィグ設定したいならこちらの方法。

```js
import Vue from 'vue';
import VeeValidate from 'vee-validate';

const config = {
  // config that you want
}

Vue.use(VeeValidate, config);
```

### ベーシックな例

inputフォームに`v-validate`ディレクティブと`name`属性を追加するだけでOKです。`name`属性はエラーメッセージの生成に利用されます。
`v-validate`ディレクティブにはルールを設定します。パイプ`|`を間に挟むことで複数のルールが適用可能です。
以下は「必須、かつ、eメールの形式であること」の例です。

```html
<input v-validate="'required|email'" name="email" type="text">
```

エラーメッセージを表示するには`errors.first`メソッドを利用することでその項目の最初のエラーが取得できます：

```html
<span>{{ errors.first('email') }}</span>
```

> Tips
> `v-validate`に定義された値はシングルクォートで囲われています。これはディレクティブに与えられた内容はJavaScriptとして評価されるためです。
> シングルクォートで囲むことで`String`型であることを明示的にする必要があります。
> `v-validate="required"`としてしまうと`required`というおそらく存在しないであろう変数や関数を参照しようとしてしまいます。

## シンタックス

バリデーションルールは`String`型での定義や、プログラマブルにしたい時は`Object`型での定義も可能です。

```js
// String
const single = 'required'
const multiple = 'required|numeric'

// Object
const single = { required: true }
const multiple = {
  require: true,
  numeric: true
}
```

### ルールのパラメーター

ルールの一部はパラメーターを持つことができます。パラメーターは複数の定義方法が可能です。

- `String`型ならカンマ区切りの値
- `Object`型なら配列の値
- `Object`型でより複雑なパラメーターならオブジェクト

```js
// String型のパラメーター
const someRule = 'included:1,2,3,4';

// Array型のパラメーター
const someRuleObj = { included: [1, 2, 3, 4] };

// Object型のパラメーター
const someCplxObj = {
  email: {
    allow_utf8_local_part: true
  }
};
```

### ルールの実例

上の内容を実例でみてみましょう。

- 必須のEメールの入力欄

```html
<input v-validate="'required|email'" type="email" name="email">
<input v-validate="{ required: true, email: true }" type="email" name="email">
```

- 必須でないユーザー名の入力欄

```html
<input v-validate="'alpha'" type="text" name="username">
<input v-validate="{ alpha: true }" type="text" name="username">
```

- 必須かつ最低6文字のパスワード入力欄

```html
<input v-validate="'required|min:6'" type="password" name="password">
<input v-validate="{ required: true, min: 6 }" type="password" name="password">
```

## エラーの表示

エラーメッセージが生成されると、エラー表示簡易化のために用意された`ErrorBag`インスタンスに保存されます。

デフォルトでは`ErrorBag`のインスタンスは`error`という名前で各コンポーネントの`computed`プロパティにインジェクトされます。
`error`という名前は競合を避けるためにコンフィグからカスタマイズ可能です。

### エラーメッセージを１つ表示する

一般的には１つのフォームに対して１つのエラーを表示することが多いと思います。これは`errors.first('fieldName')`メソッドでエラーを取得可能です。

```html
<input type="text" name="fieldName" v-validate="'required'">
<span>{{ errors.first('fieldName') }}</span>
```

> Tips
> VeeValidateのデフォルトでは１フィールドに対して１エラーしか生成しません。これはバリデーションパイプラインの高速化が理由です。
> 複数のバリデーションエラーのメッセージを同時に生成したい場合は`fastExit`オプションをコンフィグからカスタマイズしてください。
> あるいは、特定のフォームだけに適用したい場合は`continues`modifilerの適用も可能です。`v-validate.continues="'required|numeric'"`

### エラーメッセージを複数表示する

１つのフォームに複数のエラーを表示したい場合は`errors.collect('fieldName')`メソッドが利用できます。
このメソッドは１つのフィールドに紐づくエラーメッセージを配列で返します。

```html
<input type="text" name="fieldName" v-validate.continues="'required|alpha|min:5'">
<ul>
  <li v-for="error in errors.collect('fieldName')">{{ error }}</li>
</ul>
```

### 全てのエラーメッセージを表示する

`errors.all()`を使いフラットなエラーメッセージの配列を取得できます。

```html
<input type="text" name="first" v-validate.continues="'required|alpha|min:5'">

<input type="text" name="second" v-validate.continues="'required|alpha|min:5'">

<ul>
  <li v-for="error in errors.all()">{{ error }}</li>
</ul>
```

フィールド名ごとにグルーピングしたい場合は、`errors.collect()`を引数無しで利用します。
キーがフィールド名で値がエラーメッセージの配列のオブジェクトが取得できます。

```html
<input type="text" name="first" v-validate.continues="'required|alpha|min:5'">

<input type="text" name="second" v-validate.continues="'required|alpha|min:5'">

<ul>
  <li v-for="group in errors.collect()">
    <ul>
      <li v-for="error in group">{{ error }}</li>
    </ul>
  </li>
</ul>
```

## バリデーションルール

いっぱいあるよ。

https://baianat.github.io/vee-validate/guide/rules.html

## カスタムコンポーネントのバリデーション

VeeValidateはHTML5のinput要素だけでなくカスタムコンポーネントのバリデーションも対応しています。
カスタムコンポーネントでの利用はいくつか注意が必要です。このトピックではその注意点について説明します。

### どう動くか

カスタムコンポーネントを入力欄として動作させるのに`v-model`を利用して値を扱うことは一般的です。
VeeValidateはこの値を`$watch` APIを利用して監視していますが、`$watch`には制限があります。
たとえば、`v-for`のイテレーターの値は`v-for`のループのコンテキストとしてしか存在していないため監視できません。

VeeValidateは`value`のpropを監視するようフォールバックします。
もしコンポーネントが`model`コンストラクタをカスタマイズしている場合でも、正しいプロパティを検出しそれを監視します。

[このデモ](https://vuetifyjs.com/en/components/forms#example-vee-validate)はVeeValidateとVuetifyのカスタムコンポーネントを組み合わせた例です。

以上はほとんどのケースをカバーしますが、`v-model`を利用して値を取り回していない場合は対応できません。
そのようなケースではコンポーネントのコンストラクターオプションを利用することでより細かなバリデーションの挙動を設定することができます。

### コンポーネントのコンストラクターオプション

バリデーターのカスタムコンポーネントへの挙動をカスタマイズすることにより不要な属性の追加などを防ぐことができます。
これは`$_veeValidate`フィールドをカスタムコンポーネントに定義することで実現します：

```js
export default {
  // ...
  data: () => ({
    // コンポーネント内部のデータ
    innerValue: 'initial'
  })
  $_veeValidate: {
    // バリデーションの対象とするデータ
    value () {
      return this.innerValue;
    }
  },
}
```

`$_veeValidate`では`value`含めて以下が設定可能です。

| プロパティ | 種類 | 初期値 | 説明 |
|---|---|---|---|
| name | `() =>`, `string` | `undefined` | エラーメッセージの生成に使われる名前 | 
| value | `() =>`, `any` | `undefined` | バリデーションの対象となる値 |
| rejectFalse | `boolean` | `false` | `false`が`required`に対してバリデーションエラーとなるか |
| events | `string` | `input|blur` | バリデーションがトリガーされるイベント名 | 
| validator | `string` | `new` or `null` | コンポーネントがバリデータのインスタンスをどう得るか。`new`の場合は新しいバリデーターインスタンスを生成して利用する。 |