Vuelidate $each:如何验证嵌套集合?
Vuelidate $each: How can I validate a nested collection?
我很难理解可能的基本概念。我正在传递 location
作为道具。它有一个 json 列来存储 additionalAttributes
。它看起来像这样:
"additionalProperties": [
{
"integrations": [
{
"exampleVendor": {
"locationId": 123,
"positionId": 456
}
}
]
}
],
"createdAt": "",
"updatedAt": "",
...
以上是我硬编码到我的数据库 (Postgres) 中的内容,以尝试模拟数据返回时的样子。
我正在使用 vuelidate 文档的 validate collections 部分。
这是我用来尝试创建验证规则的内容:
validations: {
location: {
additionalProperties: {
$each: {
integrations: {
$each: {
exampleVendor: {
locationId: {required},
positionId: {required},
}
}
}
}
}
}
},
在我的模板中,我尝试像这样连接验证:
<select id="my-id"
name="my-id"
class="py-3 px-3 mt-1 block w-full pl-3 pr-10 py-2 text-base sm:text-sm rounded-md"
v-if="locations"
v-model.trim="$v.location.additionalProperties[0].integrations[0].exampleVendor.locationId.$model"
:class="[$v.location.additionalProperties[0].integrations[0].exampleVendor.locationId.$error ?
'focus:ring-red-500 focus:border-red-500 border-red-300' : 'focus:ring-gray-400 focus:border-gray-400 border-gray-300',]"
>
...
</select>
我使用这个组件已经有一段时间了, 有一个非常愚蠢的问题。
我也担心设置这么死板的路径additionalProperties[0].integrations[0]
真的很糟糕
我担心这个不会落后太多,但是是时候征求一些建议了。感谢您的任何建议!
编辑
@tony19 就为什么仅使用第一个值时使用数组进行了出色的调用。也许有更好的方法来做我正在做的事情;这是我数据库中的数据 可能 的更广泛的视图。除了集成之外,它现在还具有其他属性。不过现在,我只专注于此。
"additionalProperties": [
{
"integrations": [
{
"exampleVendor": {
"locationId": 123,
"positionId": 456
},
"anotherVendor": {
"foo": "abc",
"bar": "def"
},
"someOtherVendor": {
"thing": "value"
}
}
],
"anotherAttribute: {
"one": "two"
},
"possibleAttributes": [...]
}
],
我在解决这个问题的过程中学到了很多东西。更重要的问题之一是如何解决 vuelidate 认为它得到的问题。
我创建了一个 change
处理程序来深入了解 $model
值是什么。这是一个例子:
<select @change="onChange"...">...</select>
...
// start with what I know to be true.
onChange() {
console.log($v.location.additionalProperties);
}
使用上面的对象结构,然后我将移动到对象中,直到我得到这个:
console.log($v.location.additionalProperties.$each[0].integrations.$each[0]. exampleVendor.locationId.$model; // 12345
现在我有了模型的“路径”,我可以更新我的 <select>
元素:
<select id="my-locationId" name="my-locationId" class="py-3 px-3 mt-1 block w-full pl-3 pr-10 py-2 text-base sm:text-sm rounded-md"
v-model.trim="$v.location.additionalProperties.$each[0].integrations .$each[0].exampleVendor.locationId.$model"
:class="[
$v.location.additionalProperties.$each[0].integrations.$each[0].exampleVendor.locationId.$error
? 'focus:ring-red-500 focus:border-red-500 border-red-300'
: 'focus:ring-gray-400 focus:border-gray-400 border-gray-300',
]"
>
<option selected="selected" value="">Select</option>
<option
v-for="location in myLocations"
:key="location.id"
:value="location.id"
>
{{ location.name }}
</option>
</select>
现在嵌套路径是 collecting/setting 数据,我可以设置验证规则:
...
data: () => ({...}),
validations: {
location: {
additionalProperties: {
$each: {
integrations: {
$each: {
exampleVendor: {
locationId: { required },
positionId: { required },
},
},
},
},
},
},
},
...
methods: {
async save() {
this.$v.$touch();
if (this.$v.$invalid) {
this.errors = true;
} else {
try {
const params = {
location: this.location, // location is passed in as props
method: this.location.id ? "PATCH" : "POST",
};
console.log('params: ', params); // {...}
// Save to vuex or ??
} catch (error) {
console.log('there was an error:', error);
}
}
},
}
希望这对其他人有所帮助 - 它不是非常简单,我相信有更有效的方法,但这最终对我有用。
编辑 2
请务必同时遵循@tony19 的建议答案。提供的解决方案消除了我在问题中所说的“僵化”。
正如您评论的那样,additionalProperties
和 integrations
中可能有更多的数组值,迭代 这些属性比硬-更有意义仅对第一个元素进行编码访问。
Vuelidate docs for collections you linked 显示用 $each.$iter
迭代数组,所以我会为每个嵌套级别使用 <template v-for="ARRAY.$each.$iter">
:
<template v-for="(addtlProperty, i) in $v.location.additionalProperties.$each.$iter">
<template v-for="(integration, j) in addtlProperty.integrations.$each.$iter">
<select
:key="`${i}-${j}`"
v-model.trim="integration.exampleVendor.locationId.$model"
:class="[
integration.exampleVendor.locationId.$error
? 'focus:ring-red-500 focus:border-red-500 border-red-300'
: 'focus:ring-gray-400 focus:border-gray-400 border-gray-300',
]"
>
...
</select>
</template>
</template>
我很难理解可能的基本概念。我正在传递 location
作为道具。它有一个 json 列来存储 additionalAttributes
。它看起来像这样:
"additionalProperties": [
{
"integrations": [
{
"exampleVendor": {
"locationId": 123,
"positionId": 456
}
}
]
}
],
"createdAt": "",
"updatedAt": "",
...
以上是我硬编码到我的数据库 (Postgres) 中的内容,以尝试模拟数据返回时的样子。
我正在使用 vuelidate 文档的 validate collections 部分。
这是我用来尝试创建验证规则的内容:
validations: {
location: {
additionalProperties: {
$each: {
integrations: {
$each: {
exampleVendor: {
locationId: {required},
positionId: {required},
}
}
}
}
}
}
},
在我的模板中,我尝试像这样连接验证:
<select id="my-id"
name="my-id"
class="py-3 px-3 mt-1 block w-full pl-3 pr-10 py-2 text-base sm:text-sm rounded-md"
v-if="locations"
v-model.trim="$v.location.additionalProperties[0].integrations[0].exampleVendor.locationId.$model"
:class="[$v.location.additionalProperties[0].integrations[0].exampleVendor.locationId.$error ?
'focus:ring-red-500 focus:border-red-500 border-red-300' : 'focus:ring-gray-400 focus:border-gray-400 border-gray-300',]"
>
...
</select>
我使用这个组件已经有一段时间了,
我也担心设置这么死板的路径additionalProperties[0].integrations[0]
真的很糟糕
我担心这个不会落后太多,但是是时候征求一些建议了。感谢您的任何建议!
编辑
@tony19 就为什么仅使用第一个值时使用数组进行了出色的调用。也许有更好的方法来做我正在做的事情;这是我数据库中的数据 可能 的更广泛的视图。除了集成之外,它现在还具有其他属性。不过现在,我只专注于此。
"additionalProperties": [
{
"integrations": [
{
"exampleVendor": {
"locationId": 123,
"positionId": 456
},
"anotherVendor": {
"foo": "abc",
"bar": "def"
},
"someOtherVendor": {
"thing": "value"
}
}
],
"anotherAttribute: {
"one": "two"
},
"possibleAttributes": [...]
}
],
我在解决这个问题的过程中学到了很多东西。更重要的问题之一是如何解决 vuelidate 认为它得到的问题。
我创建了一个 change
处理程序来深入了解 $model
值是什么。这是一个例子:
<select @change="onChange"...">...</select>
...
// start with what I know to be true.
onChange() {
console.log($v.location.additionalProperties);
}
使用上面的对象结构,然后我将移动到对象中,直到我得到这个:
console.log($v.location.additionalProperties.$each[0].integrations.$each[0]. exampleVendor.locationId.$model; // 12345
现在我有了模型的“路径”,我可以更新我的 <select>
元素:
<select id="my-locationId" name="my-locationId" class="py-3 px-3 mt-1 block w-full pl-3 pr-10 py-2 text-base sm:text-sm rounded-md"
v-model.trim="$v.location.additionalProperties.$each[0].integrations .$each[0].exampleVendor.locationId.$model"
:class="[
$v.location.additionalProperties.$each[0].integrations.$each[0].exampleVendor.locationId.$error
? 'focus:ring-red-500 focus:border-red-500 border-red-300'
: 'focus:ring-gray-400 focus:border-gray-400 border-gray-300',
]"
>
<option selected="selected" value="">Select</option>
<option
v-for="location in myLocations"
:key="location.id"
:value="location.id"
>
{{ location.name }}
</option>
</select>
现在嵌套路径是 collecting/setting 数据,我可以设置验证规则:
...
data: () => ({...}),
validations: {
location: {
additionalProperties: {
$each: {
integrations: {
$each: {
exampleVendor: {
locationId: { required },
positionId: { required },
},
},
},
},
},
},
},
...
methods: {
async save() {
this.$v.$touch();
if (this.$v.$invalid) {
this.errors = true;
} else {
try {
const params = {
location: this.location, // location is passed in as props
method: this.location.id ? "PATCH" : "POST",
};
console.log('params: ', params); // {...}
// Save to vuex or ??
} catch (error) {
console.log('there was an error:', error);
}
}
},
}
希望这对其他人有所帮助 - 它不是非常简单,我相信有更有效的方法,但这最终对我有用。
编辑 2
请务必同时遵循@tony19 的建议答案。提供的解决方案消除了我在问题中所说的“僵化”。
正如您评论的那样,additionalProperties
和 integrations
中可能有更多的数组值,迭代 这些属性比硬-更有意义仅对第一个元素进行编码访问。
Vuelidate docs for collections you linked 显示用 $each.$iter
迭代数组,所以我会为每个嵌套级别使用 <template v-for="ARRAY.$each.$iter">
:
<template v-for="(addtlProperty, i) in $v.location.additionalProperties.$each.$iter">
<template v-for="(integration, j) in addtlProperty.integrations.$each.$iter">
<select
:key="`${i}-${j}`"
v-model.trim="integration.exampleVendor.locationId.$model"
:class="[
integration.exampleVendor.locationId.$error
? 'focus:ring-red-500 focus:border-red-500 border-red-300'
: 'focus:ring-gray-400 focus:border-gray-400 border-gray-300',
]"
>
...
</select>
</template>
</template>