VeeValidateの使い方（Vue + TypeScript + Vuetify)

# 実施内容

Vue(TypeScript)でVeeValidateを使ったバリデーションを実施したメモです。Vuetifyを使っています。Vueは、Vue.extend方式を使っています。あまり詳しい説明は記載できていません。

## 動作環境

- Node.js v12.18.3
- npm 6.14.8
- vue-cli 4.5.6
- vue 2.6.12
- vuetify 2.2.11

# 使い方

## インストール

```
npm install --save vee-validate
```

## import

```ts
import Vue from 'vue';
import { ValidationProvider, ValidationObserver, extend } from 'vee-validate';
import { required, email } from 'vee-validate/dist/rules';
```
| コンポーネント | 用途 |
|:-:|:-:|
| ValidationProvider | 指定項目でバリデーションを行う |
| ValidationObserver | 複数のバリデーションをグループ化する |
| extend | ルールを編集する |

## ルールの指定

[ルール一覧](https://logaretm.github.io/vee-validate/guide/rules.html#rules)

```ts:sample.vue

// 編集なし（デフォルトのルール・メッセージを使用
extend('email', email);

// デフォルトのメッセージを上書き
extend('required', {
  ...required,
  message: '{_field_}は必須項目です。'
});
```

`{_field_}`には、ValidationProviderの`name`要素が割り当てられる。

メッセージは、上記のように使うルールだけ日本語に書き換える方法と、デフォルトで全て日本語にする方法がある。日本語化については、[こちら](#日本語化)。
デフォルトのメッセージは、以下に記載されている。
英語→`node_modules/vee-validate/dist/locale/en.json`


## componentsに登録
そのまま。

```ts:sample.vue
export default Vue.extend({
  name: 'Login',
  components: {
    ValidationProvider,
    ValidationObserver,
  },
  ...
```

## v-text-fieldにバリデーションを追加

`v-text-field`を`validation-provider`で囲む。

```html:sample.vue
<validation-provider v-slot="{ errors }" name="User ID" rules="required">
  <v-text-field
    prepend-icon="mdi-account-circle"
    label="User ID"
    v-model="user.userId"
    :error-messages="errors"
  />
</validation-provider>

```

`v-slot`で、エラーメッセージなど様々な値を取得する。上記の例では、エラーメッセージを取得し、`v-text-field`のエラーメッセージに入力している。
ルールは複数指定可能。例　`rules="required|email"`

例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205002/d999e2f2-2692-b718-88e6-afcc14b840a5.png)

そのほかに`v-slot`で取得できる値は[こちら](https://logaretm.github.io/vee-validate/api/validation-provider.html#scoped-slot-props)。

## バリデーションのグループ化

この場合、`v-form`を`ValidationObserver`で囲む。

```html:Sample.vue
          <ValidationObserver ref="observer" v-slot="{ invalid }">
            <v-form>
              <v-container>
                <validation-provider v-slot="{ errors }" name="User ID" rules="required">
                  <v-text-field
                    prepend-icon="mdi-account-circle"
                    label="User ID"
                    v-model="user.userId"
                    :error-messages="errors"
                    @input="input"
                  />
                </validation-provider>
                <validation-provider v-slot="{ errors }" name="Password" rules="required">
                  <v-text-field
                    prepend-icon="mdi-account-lock"
                    type="password"
                    label="Password"
                    v-model="user.password"
                    :error-messages="errors"
                  />
                </validation-provider>
              </v-container>
            </v-form>
            <v-btn type="submit" @click="doLogin" :loading="loading" :disabled="invalid">
              ログイン<v-icon>mdi-login</v-icon>
            </v-btn>
          </ValidationObserver>
```

この状態では、User IdとPassword二つのバリデーションをValidationObserverで確認する。ここでも、`v-slot`で、エラーメッセージなど様々な値を取得できる。上記の例では、`invalid`で二つのバリデーションが成功しているか確認し、ログインボタンの有効・無効を制御している（`:disabled="invalid"`の部分）。したがって、User IdとPassword両方を入力しないと、ボタンが有効化しない。

そのほかに`v-slot`で取得できる値は[こちら](https://logaretm.github.io/vee-validate/api/validation-observer.html#scoped-slot-props)。

## $refsを使ったValidationObserverの制御（引っかかったところ）

vueのmethod内でバリデーションをリセットしたい時などに、`$refs`を利用して[ValidationObserver Compornent API](https://logaretm.github.io/vee-validate/api/validation-observer.html#scoped-slot-props)にアクセスすることが必要になる。ここで、Typescriptを使っていると記載方法に癖がある。
[公式ドキュメント](https://logaretm.github.io/vee-validate/guide/forms.html#programmatic-access-with-refs)に記載している方法では、`Vue.extend`のパターンには合わなかったので、以下の方法で実施した。

```ts:Sample.vue
    ...
    resetForm() {
      this.user.userId = '';
      this.user.password = '';
      (this.$refs.observer as InstanceType<typeof ValidationObserver>).reset();
    },
```

このように記載することで、`reset（）`を使えるようになる。
今回の例だと、

```html
<ValidationObserver ref="observer" v-slot="{ invalid }">
```
で検出したバリデーションのエラーを

```ts
(this.$refs.observer as InstanceType<typeof ValidationObserver>).reset();
```
でリセットすることになる。

これに時間かかった、、、

## 日本語化

最後に、メッセージを全て日本語化する。 
[公式ドキュメント](https://logaretm.github.io/vee-validate/guide/localization.html#using-the-default-i18n)

まず、`tsconfig.json`を編集する。

```json:tsconfig.json
{
  "compilerOptions": {
    // ...
    "resolveJsonModule": true,
    "esModuleInterop": true
    // ...
  }
}
```

### importその2+

localizeと、日本語メッセージが含まれる`ja.json`をimportする。また、`localize`で日本語を有効化する。

```ts:Sample.vue
// localize追加
import { ValidationProvider, ValidationObserver, localize, extend } from 'vee-validate';
// 追加
import ja from 'vee-validate/dist/locale/ja.json';

localize('ja', ja);
```

日本語のメッセージ一覧→`vee-validate/dist/locale/ja.json`

以上。