vuelidate を使用してフォーム入力を検証し、 vuetifyjs を使用してエラーメッセージを表示しています。基本的なオブジェクト検証を何とか実行して、エラーメッセージを表示することができました。
ただし、コレクションを検証するとエラーメッセージが表示されません。
[〜#〜]問題[〜#〜]
データ構造の例:
contact: {
websites: [
{
url: 'http://www.something.com',
label: 'Website',
}
]
}
検証の例:
validations: {
websites: {
$each: {
url: {
url,
}
}
},
}
テンプレートの例:
<template v-for="(website, index) in websites">
<v-layout row :key="`website${index}`">
<v-flex xs12 sm9 class="pr-3">
<v-text-field
label="Website"
:value="website.url"
@input="$v.websites.$touch()"
@blur="$v.websites.$touch()"
:error-messages="websiteErrors"
></v-text-field>
</v-flex>
</v-layout>
</template>
計算されたエラーメッセージの例:
websiteErrors() {
console.log('websites',this.$v.websites) // contains $each
const errors = []
if (!this.$v.websites.$dirty) {
return errors
}
// Issue is that all of them show must be valid, even if they are valid.
// Validation is basically broken.
// I also tried this.$v.websites.$each.url
!this.$v.websites.url && errors.Push('Must be valid url')
return errors
},
メソッドの例(更新、インデックスを渡す方法も試した):
websiteErrors(index) {
console.log('this.$v.entity.websites', this.$v.entity.websites.$each.$iter, this.$v.entity.websites.$each.$iter[index], this.$v.entity.websites.minLength, this.$v.entity.websites.$each.$iter[index].url)
const errors = []
if (!this.$v.entity.websites.$dirty) {
return errors
}
!this.$v.entity.websites.$each.$iter[index].url && errors.Push('Must be valid url')
return errors
},
ただし、これを行うと、常に真になるため、エラーが表示されることはありません。
[〜#〜]予想される[〜#〜]
vuelidate sub-collection validation にあるのと同じ例を機能させたいのですが、テンプレートでループするのではなく、プログラムでメッセージを生成したいのです。
[〜#〜]参照[〜#〜]
Vuelidateが提供する例:
import { required, minLength } from 'vuelidate/lib/validators'
export default {
data() {
return {
people: [
{
name: 'John'
},
{
name: ''
}
]
}
},
validations: {
people: {
required,
minLength: minLength(3),
$each: {
name: {
required,
minLength: minLength(2)
}
}
}
}
}
<div>
<div v-for="(v, index) in $v.people.$each.$iter">
<div class="form-group" :class="{ 'form-group--error': v.$error }">
<label class="form__label">Name for {{ index }}</label>
<input class="form__input" v-model.trim="v.name.$model"/>
</div>
<div class="error" v-if="!v.name.required">Name is required.</div>
<div class="error" v-if="!v.name.minLength">Name must have at least {{ v.name.$params.minLength.min }} letters.</div>
</div>
<div>
<button class="button" @click="people.Push({name: ''})">Add</button>
<button class="button" @click="people.pop()">Remove</button>
</div>
<div class="form-group" :class="{ 'form-group--error': $v.people.$error }"></div>
<div class="error" v-if="!$v.people.minLength">List must have at least {{ $v.people.$params.minLength.min }} elements.</div>
<div class="error" v-else-if="!$v.people.required">List must not be empty.</div>
<div class="error" v-else-if="$v.people.$error">List is invalid.</div>
<button class="button" @click="$v.people.$touch">$touch</button>
<button class="button" @click="$v.people.$reset">$reset</button>
<tree-view :data="$v.people" :options="{rootObjectKey: '$v.people', maxDepth: 2}"></tree-view>
</div>
WHAT WENT WRONG
vuelidate $each.$iter
:計算されたエラーメッセージからv-for
に移動しました[〜#〜]ソリューション[〜#〜]
これはその方法です(修正1および3):
<template v-for="(v, index) in $v.websites.$each.$iter">
<v-layout row :key="`website${index}`">
<v-flex xs12 sm9 class="pr-3">
<v-text-field
label="Website"
:value="v.$model.url"
@input="$v.websites.$touch()"
@blur="$v.websites.$touch()"
:error-messages="v.$dirty && !v.required ? ['This field is required'] : !v.url ? ['Must be a valid url'] : []"
/>
</v-flex>
</v-layout>
</template>
これが私のアップデート方法です(修正2):
updateWebsite(index, $event) {
const websites = [...this.websites];
websites[index] = $event;
this.updateVuex(`websites`, websites)
this.$v.websites.$touch()
},
もともとはこのようなものでした:
updateWebsite(index, $event) {
this.updateVuex(`websites[${index}]`, $event)
this.$v.websites.$touch()
},
[〜#〜]代替[〜#〜]
この場合はwebsite
をコンポーネント内にラップするという別のオプションがあります。これにより、計算されたエラーメッセージは共有されないため、保持できます。