Vue.js バリデーション

#### ライブラリ

[VeeValidate](https://logaretm.github.io/vee-validate/) が機能豊富でメンテナンスも継続的に行われている。[vuelidate](https://github.com/monterail/vuelidate) もよく紹介されているが、こちらは最新リリースが2018年5月リリースのv0.7.4となっている。（2019年11月時点）

##### 参考

* [Form Validation - Vue.js](https://vuejs.org/v2/cookbook/form-validation.html)
	* Alternative Patternとして[vuelidate](https://github.com/monterail/vuelidate)と[VeeValidate](https://logaretm.github.io/vee-validate/)が紹介されている

* [vee-validate と bootstrap-vue を連携させてお手軽フォームバリデーションを実現する]( https://qiita.com/mashiro/items/c77434a6a591d39441fe)
	* vuelidateよりもVeeValidateの方が直感的でおすすめとのこと

#### VeeValidateの使い方（BootstrapVueとの組み合わせ）

基本的な使い方は [UI libraries BoostrapVue](https://logaretm.github.io/vee-validate/examples/ui-libraries.html#bootstrapvue) がとても参考になる。

##### 対象バージョン

* Vue.js 2.6.10
* VeeValidate 3.0.11
* BootstrapVue 2.0.4

※ VeeValidateは3系で大きく使い方が変わっているが、VeeValidateについて検索すると古いバージョンに関する記事が多くヒットするため、参考にする際は説明されているVeeValidateのバージョンに注意すること。

##### インストール

```shell
npm install -S vee-validate
```

##### コンポーネント読み込み

グローバルに全ルール・メッセージバンドル版を読み込む場合は、main.tsで以下のように記述する。

```typescript
import Vue from 'vue';
// @ts-ignore
import { ValidationProvider } from 'vee-validate/dist/vee-validate.full';
import { ValidationObserver } from 'vee-validate';

Vue.component('ValidationProvider', ValidationProvider);
Vue.component('ValidationObserver', ValidationObserver);
```

プロダクション用には、バンドルサイズを抑えるために必要なルール・メッセージのみインポートする方がよい。（参考：[Importing validation rules](https://logaretm.github.io/vee-validate/guide/basic-validation.html#importing-validation-rules)）

提供されているルール一覧は [Validation Rules](https://logaretm.github.io/vee-validate/api/rules.html) を参照。

##### バリデーション実装

フォームコンポーネントの実装例（Form.ts）：

```vue
<template>
  <ValidationObserver ref="observer" v-slot="{ passes }">
    <b-form novalidate @submit.prevent="passes(onSubmit)">
      <ValidationProvider name="title" rules="required|max:10"
                          v-slot="{ errors, valid, validated }">
        <b-form-group label-cols-sm="3" label="Title" label-for="title">
          <b-form-input v-model="title" type="text"
            :state="validated ? valid : null"></b-form-input>
          <b-form-invalid-feedback>{{ errors[0] }}</b-form-invalid-feedback>
        </b-form-group>
      </ValidationProvider>
      <b-form-group>
        <b-row class="justify-content-center">
          <b-button class="col-sm-4" type="submit" variant="primary">Submit</b-button>
        </b-row>
      </b-form-group>
    </b-form>
  </ValidationObserver>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';

@Component()
export default class Form extends Vue {
  private title: string = '';
  private onSubmit(): void {
    ...
  }
}
</script>
```

[Validation Provider](https://logaretm.github.io/vee-validate/guide/validation-provider.html#scoped-slot-data) コンポーネントでは、rules属性に適用するバリデーションルール（上記の場合は必須かつ10文字以内というルール）を列挙し、name属性にエラーメッセージに使われるフィールド名を指定する。（参考：[Customizing the filed name](https://logaretm.github.io/vee-validate/guide/displaying-errors.html#customizing-the-field-name)）`b-form-input` のstate属性を `validated ? valid : null` と指定することで、「初期表示状態ではエラーメッセージを表示せずに、初回入力後にバリデーション違反があれば表示する」という制御をしている。

[ValidationObserver](https://logaretm.github.io/vee-validate/guide/validation-observer.html#validation-observer)  コンポーネントを使うことで、フォーム全体のバリデーション状態に基づいて制御が記述できる。上記では `@submit.prevent="passes(onSubmit)"` により、フォーム送信時にバリデーションを実行して、バリデーションを通過した場合のみ `onSumit` を実行するようにしている。