https://github.com/mashiro/vee-bootstrap-example
お手軽に使えて非常に便利な vee-validate の errors を指定する部分をコンポーネントに切り出してさらに簡単に扱えるようにする。
bootstrap-vue では form-validation の例として vuelidate があげられているが、 vee-validate のほうが使い方がシンプルで v-if で非表示にした要素は validation の対象にならないなど極めて直感的に扱えるのでこちらが個人的におすすめ。
<template>
<b-form-group
v-bind="$attrs"
v-on="$listeners"
:invalidFeedback="invalidFeedback"
:state="state"
>
<slot
:$name="name"
:$state="state"
/>
</b-form-group>
</template>
<script>
export default {
inject: ["$validator"],
props: {
name: {
type: String,
required: true
}
},
computed: {
errors() {
return this.$validator.errors;
},
state() {
return this.errors.has(this.name) ? false : null;
},
invalidFeedback() {
return this.errors.first(this.name);
}
}
};
</script>
b-form-group
には bootstrap の feedback を扱うための便利なプロパティがあるのでそこに vee-validate から取得した情報を設定してあげるような wrapper を用意してあげればいい。
$validator
を inject することにより親コンポーネントの mixin で provide された validator インスタンスを得ることができるのでそこから errors を取得することによりバリデーションの状態を取得することができる。
errors からあるグループの状態を得るために名前が必要なため form-group に name プロパティを持たせている。
また、この name プロパティは子コンポーネントの from-input などでも同じものを用いるため scope で再利用できるようにしている。
state も入力コンポーネントの状態を変更するために必要なのでこちらも scope に渡す。
実際に使うとこの様になる。
<my-form-group name="email" label="Email">
<template slot-scope="scope">
<b-form-input
type="email"
:name="scope.$name"
:state="scope.$state"
v-model="form.email"
v-validate="{ required: true, email: true }"
/>
</template>
</my-form-group>
一般的な Vue のアプローチから外れず極めてシンプルに実現できたのではないでしょうか。
vee-validate の若干よろしくない点としては inject すると errors
, fields
というあきらかにぶつかりそうなフィールド名を使用するので設定でプリフィクスをつけるなどして変更しておくといい。
自動インジェクションも無駄な負荷につながるので無効でいいでしょう。
Vue.use(VeeValidate, {
inject: false,
errorBagName: "vvErrors",
fieldsBagName: "vvFields"
});