前回に続きまして、Vueでバリデーションを行う方法を紹介しようと思います。
調べたりしたのですが、自分の力では理解できる記事が少なかったので、備忘録として残しておきたいと思います。
今回は前回の動的にコンポーネントを追加する機能を付けたままバリデーションを行うようにしてあります。
開発環境
- MaOS
- VSCode
- vue.js 2.x
- vue/cli 4.5.13
- Bootstrap-vue
- veeValidate 7.7.6
参考にした記事
Vue JS VeeValidate + BootstrapVue – Form Validation Example
やり方
まずは、親のコンポーネントからです。
<template>
<b-container fluid>
<b-row class="mt-5 d-flex justify-content-center">
<b-col cols md="8" xl="8">
<b-row class="mb-5">
<b-col cols="12">
<ValidationObserver ref="observer">
<Children></Children>
<component v-for="field in fields" v-bind:is="field.type" v-bind:key="field.id"></component>
<b-button block type="button" v-on:click="addForm('Children')" class="border-0" style="background-color: rgba(191, 202, 63, 0.99);">観光地を追加</b-button>
</ValidationObserver>
</b-col>
</b-row>
</b-col>
</b-row>
</b-container>
</template>
<script>
import Children from '../components/Children.vue'
import { ValidationObserver } from 'vee-validate'
export default {
data: () => ({
tripTran: {
title: '',
days: '',
},
fields: [],
count: 0,
}),
components: {
Children,
ValidationObserver,
},
methods: {
addForm: function(type){
this.fields.push({
type: type,
id: this.count++
})
},
}
}
</script>
次に子のコンポーネントになります。
<template>
<div>
<b-row class="justify-content-end d-flex mt-3 mb-3">
<b-col cols="3">
<ValidationProvider name="移動手段" rules="required">
<b-form-group slot-scope="{ valid, errors }">
<b-form-input
type="text"
v-model="tripTransport.howTo"
placeholder="移動手段"
v-bind:state="errors[0] ? false : (valid ? true : null)">
</b-form-input>
<b-form-invalid-feedback>
{{ errors[0] }}
</b-form-invalid-feedback>
</b-form-group>
</ValidationProvider>
</b-col>
<b-col cols="3">
<ValidationProvider name="所要時間" rules="required|numeric">
<b-form-group slot-scope="{ valid, errors }">
<b-form-input
type="text"
v-model="tripTransport.howLong"
placeholder="所要時間"
v-bind:state="errors[0] ? false : (valid ? true : null)">
</b-form-input>
<b-form-invalid-feedback>
{{ errors[0] }}
</b-form-invalid-feedback>
</b-form-group>
</ValidationProvider>
</b-col>
<b-col cols="3">
<ValidationProvider name="料金" rules="required|numeric">
<b-form-group slot-scope="{ valid, errors }">
<b-form-input
type="text"
v-model="tripTransport.fee"
placeholder="料金"
v-bind:state="errors[0] ? false : (valid ? true : null)">
</b-form-input>
<b-form-invalid-feedback>
{{ errors[0] }}
</b-form-invalid-feedback>
</b-form-group>
</ValidationProvider>
</b-col>
</b-row>
<b-row>
<b-col cols="4">
<ValidationProvider name="観光地" rules="required">
<b-form-group slot-scope="{ valid, errors }">
<b-form-input
type="text"
v-model="tripTransport.spot"
placeholder="観光地"
v-bind:state="errors[0] ? false : (valid ? true : null)">
</b-form-input>
<b-form-invalid-feedback>
{{ errors[0] }}
</b-form-invalid-feedback>
</b-form-group>
</ValidationProvider>
</b-col>
<b-col cols="4">
<ValidationProvider name="滞在時間" rules="required|numeric">
<b-form-group slot-scope="{ valid, errors }">
<b-form-input
type="text"
v-model="tripTransport.hours"
placeholder="滞在時間"
v-bind:state="errors[0] ? false : (valid ? true : null)">
</b-form-input>
<b-form-invalid-feedback>
{{ errors[0] }}
</b-form-invalid-feedback>
</b-form-group>
</ValidationProvider>
</b-col>
<b-col cols="4">
<ValidationProvider name="料金" rules="required|numeric">
<b-form-group slot-scope="{ valid, errors }">
<b-form-input
type="text"
v-model="tripTransport.money"
placeholder="料金"
v-bind:state="errors[0] ? false : (valid ? true : null)">
</b-form-input>
<b-form-invalid-feedback>
{{ errors[0] }}
</b-form-invalid-feedback>
</b-form-group>
</ValidationProvider>
</b-col>
</b-row>
</div>
</template>
<script>
import { ValidationProvider } from 'vee-validate'
export default {
componets: {
ValidationProvider
},
data: () => ({
tripTransport: {
spot: '',
hours: '',
money: '',
howTo: '',
howLong: '',
fee: '',
}
}),
}
</script>
解説
それでは解説をしていきたいと思います。
まず、veevalidate
を使用してバリデーションを行うには、ValidationObserver
とValidationProvider
というものをimportする必要があります。
ValidationObserver
でフォーム全体を囲むようにして、ValidationProvider
で個々のフォームを囲むという感じです。
ValidationObserver
<ValidationObserver>
タグ内には、ref="observer"
を書く必要があるみたいです。
参考にした記事の中では、<b-form>
タグを作成しておりましたが、動的にコンポーネントを追加しようと思ったときに、上手くできなかった
ので、今回は使っておりません。
<template>
<ValidationObserver ref="observer">
<b-form slot-scope="{ validate }"
v-on:submit.prevent="validate().then(handleSubmit)">
</b-form>
<b-button type="submit">送信</b-button>
</ValidationObserver>
</template>
<script>
export default{
methods: {
handleSubmit(){
console.log('hello')
}}
}
</script>
ValidationProvider
<ValidationProvider>
タグ内には、rules
を書くようにします。
このrules
の中にrequired
を入れれば必須項目
になったりと、バリデーションのルールを設定します。
<ValidationProvider name="移動手段" rules="required">
<b-form-group slot-scope="{ valid, errors }">
<b-form-input
type="text"
v-model="tripTransport.howTo"
placeholder="移動手段"
v-bind:state="errors[0] ? false : (valid ? true : null)">
</b-form-input>
<b-form-invalid-feedback>
{{ errors[0] }}
</b-form-invalid-feedback>
</b-form-group>
</ValidationProvider>
<script>
import { ValidationProvider } from 'vee-validate'
export default {
data: () => ({
tripTransport: {
spot: '',
hours: '',
money: '',
howTo: '',
howLong: '',
fee: '',
}
}),
component: {
ValidationProvider
}
}
</script>
slot-scope
とv-model
、v-bind:state
、<b-form-invalid-feedback>
を記述します。
slot-scope
とv-bind:state
がどういう仕組みなのかは自分もわかって無いです。
ただ、v-bind:state
でバリデーションがエラーがどうかを判定していると思われます。
v-model
はscript
内に記述したdata
と入力内容を結びつける役割をします。
ただ、なんでこれを記述する必要があるのかは自分もわかりません。
b-form-invalid-feedback
はその後ろに{{ errors[0] }}
を持ってきて、エラー文を表示するようにしてあります。
まとめ
バリデーションには手こずりましたので、どなたかの助けになればと思います。
バリデーションは色々な場合を考えなきゃいけないことが多いので大変だなと思いました。
地道に書こうかと思っておりましたが、veeValidateが使えたので良かったです。
地道に書くよりもveeValidateを使う方が楽なのかなと思います。