How to Use v-model for Nested Properties? #12432
-
Hi everyone, I am having trouble using v-model with nested properties in Vue 3. I am trying to bind inputs to both top-level and nested properties in my data. It works fine for top-level properties like Here is a simple example of my code: <script setup lang="ts">
type Employer = {
country: string
}
type Experience = {
company_name: string
employer: Employer
}
const fields = [
{
name: 'company_name'
},
{
name: 'employer.country'
}
]
const records = reactive<Experience[]>([
{
company_name: 'X Company',
employer: {
country: 'USA'
}
}
])
</script>
<template>
<div>
<template
v-for="(field, fieldIndex) in fields"
:key="fieldIndex"
>
<div
v-for="(record, recordIndex) in records"
:key="recordIndex"
>
<input v-model="record[field.name]">
</div>
</template>
</div>
</template> When I use v-model for I think the problem is because of the dot notation ( If anyone knows how to fix this or has any ideas, I would really appreciate it. Thanks! |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 2 replies
-
The problem is that your code effectively does this: myObject['foo.bar'] which Javascript doesn't understand. You can only access properties that are present directly on the object with the bracket synax. To make it work, you could write getter/setter functions for nested properties. function getNested(object: Record<string, any>, path: string) {
let result = object;
for (const propertyName of path.split('.')) {
if (!propertyName || !(propertyName in result)) {
return undefined;
}
result = result[propertyName];
if (!result || typeof result !== 'object') {
break;
}
}
return result;
}
function setNested(object: Record<string, any>, path: string, value: unknown) {
let currentObject = object;
const splitPath = path.split('.');
for (let i = 0; i < splitPath.length; i++) {
const propertyName = splitPath[i];
if (!propertyName || !(propertyName in currentObject)) {
return;
}
if (i === splitPath.length - 1) {
currentObject[propertyName] = value;
return; // Success!
}
currentObject = currentObject[propertyName];
if (!currentObject || typeof currentObject !== 'object') {
break;
}
}
console.log('invalid path!')
} But you can't use it directly with <input
:value="getNested(record, field.name)"
@input="e => setNested(record, field.name, e.target.value)"
> |
Beta Was this translation helpful? Give feedback.
The problem is that your code effectively does this:
which Javascript doesn't understand. You can only access properties that are present directly on the object with the bracket synax.
To make it work, you could write getter/setter functions for nested properties.
Here is a quick implementation (can probably be written better):