Vue.jsを使ってて、フロントサイドのバリデーションには VeeValidate が便利


先日、フロントサイドのバリデーションにはvalidatorjsが便利という記事を拝見し、現在作っているシステムで使ってみようとしたのですが、挫折しました。

理由としては、複雑なフロントを作ろうとしているためで、下記の要件を満たす必要がありました。

  • 1:n のデータで、ユーザーが追加できる要素がある (例: 複数メールアドレス登録)
  • ページローティング直後はバリデーションしない
    • ユーザーがインプット開始時に、 入力中の要素のみ バリデーション
  • フォームを送信する直前に 全ての要素 に対してバリデーション
    • エラーのある要素は赤くする
  • エラーのある 要素の直後 に、 「メールアドレスは必須項目です。」などというメッセージを表示
  • バリデーションのルールは一箇所にまとめたい。入力中と送信時でほぼ使いまわしたい。

そこで見つけたのが VeeValidate です。

素晴らしかったので使い方を書いておきます。

単純なバリデーション

Emailを送信するフォームがあって、下記のタイミングでバリデーションが働くようにします。

  • 入力時
  • 送信時

Promiseでできるのが気持ちいいですね。またバリデーションのルールを <input> に置けるのが個人的には好きです。

VeeValidationSimple.vue
<template>
  <div>
    <input
       name="email"
       v-model="email"
       v-validate="'required|email'"
       :class="{'has-error': errors.has('email')}">
    <p v-if="errors.has('email')" class="alert-danger">
      {{ errors.first('email') }}
    </p>

    <button @click="register">Register</button>
  </div>
</template>

<script>
import Vue from 'vue'
import VeeValidate from 'vee-validate'

Vue.use(VeeValidate)

export default {
  data () {
    return {
      email: ''
    }
  },
  methods: {
    register () {
      this.$validator.validateAll().then((result) => {
        if (!result) {
          alert(this.errors.all())
          return
        }
        alert('Hello, ' + this.email)
      })
    }
  }
}
</script>

<style>
.alert-danger {
  color: red;
}
.has-error {
  border-color: red;
}
</style>

複数の要素に対するバリデーション

意外と簡単でした。
nameで識別しているらしいので、関連する属性値に連番を振ってあげればOKです。

VeeValidationMultiple.vue
<template>
  <div class="hello">

    <!-- 要素に連番を振る -->
    <div v-for="(account, i) in accounts">
      <input
         :name="'email' + i"
         v-model="account.email"
         v-validate="'required|email'"
         :class="{'has-error': errors.has('email' + i)}">
      <p v-if="errors.has('email' + i)" class="alert-danger">
        {{ errors.first('email' + i) }}
      </p>
    </div>

    <p>
      <button @click="addAccount">Add Account</button>
      <button @click="register">Register</button>
    </p>
  </div>
</template>

<script>
import Vue from 'vue'
import VeeValidate from 'vee-validate'

Vue.use(VeeValidate)

export default {
  data () {
    return {
      // v-forで回す要素は、オブジェクトの配列にする
      accounts: [{
        email: ''
      }]
    }
  },
  methods: {

    // 追加
    addAccount () {
      this.accounts.push({
        email: ''
      })
    },

    register () {
      this.$validator.validateAll().then((result) => {
        if (!result) {
          alert(this.errors.all())
          return
        }
        alert('Hello, ' + this.accounts)
      })
    }

  }
}
</script>

<style>
.alert-danger {
  color: red;
}
.has-error {
  border-color: red;
}
</style>

こんな感じになります。

ちゃんと、後から追加された要素に対してもバリデーションが効いています。

参考

ドキュメントも豊富です。

今回のソースコードも貼っておきます。
https://github.com/acro5piano/vue-cli-test/blob/master/src/components/VeeValidation.vue