Vue.js + Laravel8.4でVeeValidateを使ってバリデーションしてみる

##【開発環境】
Windows 10 HOME
PHP 7.4.7
MySQL

Laravel Framework 8.4
vue            : 2.6.12
vue-router   : 3.5.1
vee-validate : 3.4.9


##【目次】

|  | 　　項目　　　　　|
|:----:|:-------------|
| - | [はじめに](#はじめに) |
| - | [前提条件](#前提条件) |
| - | [インストール](#インストール) |
| - | [使い方](#使い方) |
| - | [解説](#解説) |
| - | [最後に](#最後に) |
| - | [参考](#参考) |




#はじめに

Vue.js + Laravel 8.4で [VeeValidate](https://vee-validate.logaretm.com/v3) を使ってバリデーションしてみました。

Vue.js側のバリデーションを調べてみたところ
いくつかありかしたが今回はVeeValidateを使ってみました。



Vue.js + Laravelの勉強をしており、
下記の記事を見て動かしてみましたが
CRUDの最小構成のシステムで
もっと機能を追加したという事で、今回の記事にしたという経緯です。
(2021年6月11日現在)

[Vue.js + LaravelでシンプルなSPA構築チュートリアル：概要編](https://qiita.com/minato-naka/items/2d2def4d66ec88dc3ca2)

Vue.jsとLaravelによるSPA記事で下記の記事で構成しています。
(未リンクの記事はこれから作成予定)

■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
[**Vue.js + Laravel8.4でVeeValidateを使ってバリデーションしてみる**](https://qiita.com/silversink8888/items/e0e90f1851c7475cea3a)
<font color="red">**↑↑↑↑↑↑今回はここです↑↑↑↑↑↑**</font>

[Vue.js + Laravel8.4でAjaxのエラーハンドリングしてみる](https://qiita.com/silversink8888/items/51c8ced17600ca17604f#%E4%BD%BF%E3%81%84%E6%96%B9)
[Vue.js + Laravel8.4でLaravel側もバリデーションしてみる]
[Vue.js + Laravel8.4でLaravel側のAPIの認証処理してみる]

■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■


[Github](https://github.com/silversink8888/vue-laravel-spa)
でもソースを公開していますので参考にして下さい。

#前提条件

参考にさせて頂いた記事との開発環境の相違箇所。

・Laravel のバージョンが異なる

Laravel 6.*

```
App\Task;
```
↓

Laravel 8.4

```
App\Models\Task;
```

上記のようにLaravel 8.*ではコントローラーのパスが
変更されていますので適宜変更して下さい。

・入力項目のCSSを若干変更しています。
・DBはMySQLを使用

#インストール

ターミナルを開き
対象ディレクトリで下記のコマンド実行します。

```powershell
npm install vee-validate
```


#使い方

``＜script＞`` 部分の修正。

```resources/js/components/TaskCreateComponent.vue
<script>
    import Vue from 'vue'
    import {
        ValidationObserver,
        ValidationProvider,
        localize,
        extend,
    } from 'vee-validate'

  // ルール設定
    import * as rules from 'vee-validate/dist/rules'
    for (let rule in rules) {
        extend(rule, rules[rule])
    }


  // 日本語化
    import ja from 'vee-validate/dist/locale/ja'
    localize('ja', ja)

    // コンポーネント設定
    Vue.component('ValidationProvider', ValidationProvider)
    Vue.component('ValidationObserver', ValidationObserver) 

    export default {
        data: function () {
            return {
                task: {}
            }
        },
        methods: {
            submit() {

                this.$refs.observer.validate().then((result) => {
                    if(result) {
                        // OK
                        axios.post('/api/tasks', this.task)
                        .then((res) => {
                            this.$router.push({name: 'task.list'});
                        });
                    }
                })

            }
        }
    }
</script>

```


``＜template＞``側の修正

今回は下記にバリデーションを設定します。

・Title
・Content


```resources/js/components/TaskCreateComponent.vue
<template>
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-sm-6">
                <ValidationObserver ref="observer" v-slot="{ invalid }">
                <form v-on:submit.prevent="submit">
                    <div class="form-group row">
                        <label for="title" class="col-sm-3 col-form-label">Title</label>
                        <ValidationProvider 
                            name="title" 
                            rules="required|min:5|max:30" 
                            v-slot="{ errors }"
                        >
                            <input type="text" name="title" class="col-sm-9 form-control" v-model="task.title">
                            <div class="text-danger">{{ errors[0] }}</div>
                        </ValidationProvider>
                    </div>

                    <div class="form-group row">
                        <label for="content" class="col-sm-3 col-form-label">Content</label>
                        <ValidationProvider 
                            name="content" 
                            rules="required|min:10|max:50" 
                            v-slot="{ errors }"
                        >
                            <input type="text" class="col-sm-9 form-control" name="content" v-model="task.content">
                            <div class="text-danger">{{ errors[0] }}</div>
                        </ValidationProvider>
                    </div>

                    <div class="form-group row">
                        <label for="person-in-charge" class="col-sm-3 col-form-label">Person In Charge</label>
                        <input type="text" id="person-in-charge" class="col-sm-9 form-control" v-model="task.person_in_charge">
                    </div>

                    <div>
                        <button type="submit" :disabled="invalid" class="btn btn-primary">Submit</button>
                    </div>
                </form>
                </ValidationObserver>
            </div>
        </div>
    </div>
</template>
```

新規登録画面で文字を入力してみると
赤文字でバリデーションが表示されています。

![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669259/fe113eb6-d9e6-b878-7d7c-aca5953838fb.gif)




#解説

##### ---- モードについて

mode="モード"で設定することができます。

aggressive：入力値を変更するたび
passive：フォームが送信時
lazy：フォーカスが外れた時 or 選択が変更時（blur or change）
eager：aggressiveとlazyのミックス

[vee-validate公式](https://vee-validate.logaretm.com/v2/guide/interaction.html)

>VeeValidate comes with 4 interaction modes out of the box:

>[aggressive]: this is the default behavior and it validates whenever an input event is emitted.
[passive]: doesn't validate on any event, so you can only validate manually.
[lazy]: validates on change or blur depending on the input type.
[eager]: when the field is valid or has not yet been interacted with, it will validate on change. When the field becomes invalid due to the first validation, it will validate on input for as long the field is invalid. When the field is valid again, it will go back to validating on change. It is a mix between the aggressive and lazy modes.


何となくeagerが良いのかと。

```resources/js/components/TaskCreateComponent.vue
<ValidationProvider 
    name="title" 
    rules="required|min:5|max:30" // 5-30文字で入力必須
    v-slot="{ errors }"       //エラー判定のスイッチみたいなもの
>
```


【ValidationProvider】 
フォーム部品のエラーを監視。

【ValidationObserver】
フォーム全体を監視。
フォーム全体のバリデーションの通過の判定。

```resources/js/components/TaskCreateComponent.vue
submit() {
    this.$refs.observer.validate().then((result) => {
        if(result) {
            // OK
            axios.post('/api/tasks', this.task)
            .then((res) => {
                this.$router.push({name: 'task.list'});
            });
        }
    })
}
```

この2つをタグに設定すると
バリデーションを通過するまで送信ボタンを無効にする。

<font color="red">**v-slot="{ invalid }**</font>
<font color="red">**:disabled="invalid"**</font>

```resources/js/components/TaskCreateComponent.vue
<ValidationObserver ref="observer" v-slot="{ invalid }">
・・・
	<button type="submit" :disabled="invalid" class="btn btn-primary">Submit</button>
</ValidationObserver>
```



commit：[VeeValidate 新規登録画面](https://github.com/silversink8888/vue-laravel-spa/commit/1c9cc2c4dd9de1f3d7ced49bff4667942cc4e172)

#最後に


ご覧頂きありがとうございました。

Vue.jsは勉強して日が浅く、
間違い等があるかもしれません。

修正点等ありましたらコメント下さい。


#参考

[Vue.jsでVeeValidateを使ってバリデーション](https://scramblenote.com/article/vue-veevalidate)