Reputation: 1064
I have an array of objects with the following structure
varientSections: [
{
type: "",
values: [
{
varientId: 0,
individualValue: ""
}
]
}
]
I created a custom validation called isDuplicate, which checks for duplicate value for the property "type". For example
varientSections: [
{
type: "Basket",
values: [
{
varientId: 0,
individualValue: ""
}
]
},
{
type: "Basket", // ERROR: Duplicate with the "above" object
values: [
{
varientId: 1,
individualValue: ""
}
]
}
],
I was able to get my custom validation to work. However, the $invalid property will be false for all the objects present in the array. Hence, all the objects in the array will be highlighted in red
Below is my validation code:
validations: {
varientSections: {
$each: {
type: {
required,
isDuplicate(type, varient) {
console.log(varient);
const varientIndex = this.varientSections.findIndex(
v => v.type === type
);
var isWrong = true;
this.varientSections.forEach((varObject, index) => {
if (index !== varientIndex) {
if (varObject.type === varient.type) {
isWrong = false;
}
}
});
return isWrong;
}
},
values: {
$each: {
individualValue: {
required
}
}
}
}
}
},
Upvotes: 7
Views: 20404
Reputation: 71
In vue3 composable you should use helpers.forEach
function:
import { useVuelidate } from "@vuelidate/core";
import { helpers, required } from "@vuelidate/validators";
const form = reactive({
users: [
{
name: "John"
value: "Doe"
}
]
})
const rules = {
users: {
$each: helpers.forEach({
name: { required },
value: { required }
})
}
}
const $v = useVuelidate(rules, form)
Upvotes: 2
Reputation: 314
this is worked for me
<b-row v-for="(field,index) in fields" :key="index">
<b-colxx lg="6">
<b-form-group :label="$t('target.name')">
<b-form-input v-model="field.name" :state="!$v.fields.$each[index].name.$error"/>
<b-form-invalid-feedback v-if="!$v.fields.$each[index].name.required">name is required</b-form-invalid-feedback>
</b-form-group>
</b-colxx>
<b-colxx lg="6">
<b-form-group :label="$t('target.value')">
<b-form-input v-model="field.value" :state="!$v.fields.$each[index].value.$error"/>
<b-form-invalid-feedback v-if="!$v.fields.$each[index].value.required">value is required</b-form-invalid-feedback>
</b-form-group>
</b-colxx>
</b-row>
.
data() {
return {
fields: [
{name: null, value: null},
{name: null, value: null} ]
}
},
.
validations: {
fields: {
$each: {
name: {
required
},
value: {
required
}
}
},
},
Upvotes: 0
Reputation: 560
I had the exact same need and found that the solution was quite simple once you wrap your head around what you're trying to do. Your validator needs to trigger only if the current item is a duplicate of any previous items.
Something like this:
validations: {
varientSections: {
$each: {
isUnique(currItem, itemArr) {
// Find the index of the first item in the array that has the same type
var firstIdx = itemArr.findIndex((item /*, index, arr*/) => currItem.type === item.type );
// If it's the same as the current item then it is not a duplicte
if(currItem === itemArr[firstIdx])
return true;
// All others are considered duplicates
return false;
},
type: { required }
}
}
}
Upvotes: 0
Reputation: 3388
Should be something like this.
<div v-for="(vs, index) in varientSections" :key="index">
<input :class="{'is-error': $v.varientSections.$each[index].type.$error}" type="text" v-model="vs.type">
<input :class="{'is-error': $v.varientSections.$each[index].value.$error}" type="text" v-model="vs.value>
</div>
Change the error class to fit your need.
Upvotes: 6