Vue.JSでフォームのvalidationを行う

vue.jsでvalidation付きフォームを作った。

#基本機能

・フォームが正しく入力されているかリアルタイムで出る
・送信ボタンを押した時、全フォームが正しく入力されているか判定して処理を分ける

ようにしている。
今はフォームが空か否かで判定しているが、評価項目（文字数制限など）は比較的簡単に追加できる。

![vueform preview](https://qiita-image-store.s3.amazonaws.com/0/78136/6577ae12-7977-6047-cebd-2ae647cc6d29.png)

#実装方法
validationを行うには[vue-validator](https://github.com/vuejs/vue-validator)というライブラリを使うことも可能だが、簡単なvalidationだけではわざわざ使うほどでもない。

公式にある[firebase+vuejsでのexample](http://vuejs.org/examples/firebase.html)を参考に実装した。

今回のソースコード:[github](https://github.com/growsic/JS/blob/master/VueJS/vueForm/vueForm.html)

##validationを作る
今回は
* title
* description
* date
* location
からなるフォームを作る。

入力された情報はnewEventに保持する。
それぞれの項目に対し、booleanをもつvalidationを作成する。
 
```js
data: {
      newEvent: {
        title: '',
        description: '',
        date: '',
        location: ''
      },
      validation: {
        title: false,
        description: false,
        date: false,
        location: false
      }
    },
```

##validationを行うfilterを作る
HTMLソース内でそれぞれの入力にたいして評価を行うfilterを作成する。
今回は空白か否かのみを作成しているが、ここに評価を追加すれば他の評価方法を追加できる。
例えば公式のexampleではemailアドレスになっているか正規表現でチェックをしているし、文字数制限を課すこともできる。

```js
 filters: {
      titleValidator: {
        write: function (val) {
          this.validation.title = !!val
          return val
        }
      },
      descriptionValidator: {
        write: function (val) {
          this.validation.description = !!val
          return val
        }
      },
      dateValidator: {
        write: function (val) {
          this.validation.date = !!val
          return val
        }
      },
      locationValidator: {
        write: function (val) {
          this.validation.location = !!val
          return val
        }
      }
    },
```
ちなみに、ソースコード内の

```
this.validation.title
```
などは先ほど宣言したdataの中のvalidationの要素である。
filterで評価した結果がvalidationの要素に格納される。

##HTMLソース内で入力項目をfilterに通す

```html
<form id="form" v-on="submit:addEvent">
    <p>title:<input v-model="newEvent.title | titleValidator"></p>
    <p>description:<input v-model="newEvent.description | descriptionValidator"></p>
    <p>data:<input v-model="newEvent.date | dateValidator"></p>
    <p>location:<input v-model="newEvent.location | locationValidator"></p>
    <input type="submit" value="Add event">
  </form>

```
v-modelは編集可能な要素に対して双方向データバインディングを提供する（[参考](https://gist.github.com/koba04/9776792)）

```js
v-model="newEvent.title | titleValidator"
```
でdataで宣言したnewEvent.titleに対し、filterで作成したtitleValidatorに通す。
titleValidatorの評価結果はdataのvalidation.titleに随時格納される。

##エラーであれば表示する
v-showにbooleanを渡すと、trueの場合のみ表示できるようにできる。
ここに書く要素のvalidationを渡すことで、エラーの場合のみ表示するようにできる。

```html
  <ul class="errors">
    <li v-show="!validation.title">title cannot be empty.</li>
    <li v-show="!validation.description">description cannot be empty.</li>
    <li v-show="!validation.date">date cannot be empty.</li>
    <li v-show="!validation.location">location cannot be empty.</li>
  </ul>
```

##エラーの有無を常時監視する
入力フォームのvalidationの中に、一つでもfalseがあるか確認するようにする。
常時計算が行われるcomputedにて、booleanを返すisValidを用意しておく。

```js
computed: {
      isValid: function () {
        var valid = true
        for (var key in this.validation) {
          if (!this.validation[key]) {
            valid = false
          }
        }
        return valid
      }
    },
```

validationの全ての要素を確認していって、一つでもfalseが見つかったらをfalseを返す。

```js
  methods: {
      addEvent: function (e) {
        e.preventDefault()
        if (this.isValid) {
          console.log("success")
        }else{
          console.log("need edit")
        }
      },
    }
```

##addボタンが押されたらisValidの値に基づき処理を変える

```html
<form id="form" v-on="submit:addEvent">
    <!--中略-->
    <input type="submit" value="Add event">
  </form>
```
formにてsubmitが押されたら、addEventメソッドが実行される。

```js
    methods: {
      addEvent: function (e) {
        e.preventDefault()
        if (this.isValid) {
          console.log("success")
        }else{
          console.log("need edit")
        }
      },
    }
```
addEventが実行されたら、if文でisValidを評価して処理を分ける。

## Vue.js参考書籍
[Vue.js入門 基礎から実践アプリケーション開発まで](https://www.amazon.co.jp/gp/product/B07J6FP6NQ/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=B07J6FP6NQ&linkCode=as2&tag=hirocode-22&linkId=5614b4d30cf87df8eb08e657dacdfdb7)