I am having a really hard time trying to grasp the likely elementary concept(s). I am passing a location
in as a prop. It has a json column to store additionalAttributes
. It looks something like this:
"additionalProperties": [
{
"integrations": [
{
"exampleVendor": {
"locationId": 123,
"positionId": 456
}
}
]
}
],
"createdAt": "",
"updatedAt": "",
...
The above is what I've hard-coded into my database (Postgres) to attempt to mock what the data will look like when it comes back.
I am working from the validate collections portion of the vuelidate documentation.
Here is what I am using to attempt to create the validation rule:
validations: {
location: {
additionalProperties: {
$each: {
integrations: {
$each: {
exampleVendor: {
locationId: {required},
positionId: {required},
}
}
}
}
}
}
},
In my template, I'm trying to connect the validations like this:
<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>
I've been working with this component for quite a while and have already asked a really silly question.
I am also concerned that by setting such a rigid path additionalProperties[0].integrations[0]
is really bad.
I fear this one isn't too far behind but it's time to ask for some advice. Thank you for any suggestions!
EDIT
@tony19 made an excellent call about why the array if only the first value is being used. Perhaps there is a better way to do what I'm doing; here is a wider view of what the data in my database could look like. It has additional properties now beyond just integrations. For now, I'm only focused on that though.
"additionalProperties": [
{
"integrations": [
{
"exampleVendor": {
"locationId": 123,
"positionId": 456
},
"anotherVendor": {
"foo": "abc",
"bar": "def"
},
"someOtherVendor": {
"thing": "value"
}
}
],
"anotherAttribute: {
"one": "two"
},
"possibleAttributes": [...]
}
],
There are quite a few things I've learned while working through this. One of the more important being how to troubleshoot what vuelidate thought it was getting.
I created an change
handler to provide insight to what the $model
value was. Here is an example:
<select @change="onChange"...">...</select>
...
// start with what I know to be true.
onChange() {
console.log($v.location.additionalProperties);
}
Using the above object structure, I'd then move into the object until I ended up with this:
console.log($v.location.additionalProperties.$each[0].integrations.$each[0]. exampleVendor.locationId.$model; // 12345
Now that I had the "path" to the model, I could update my <select>
element:
<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>
Now that the nested path was collecting/setting the data, I could set up the validation rules:
...
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);
}
}
},
}
Hope this helps someone else - it wasn't super straight forward & I'm sure there is a more effective way, but this ended up working for me.
EDIT 2
Please be sure to follow @tony19's suggested answer as well. The solution provided removes the "rigidity" I was speaking about in my question.