Consider the following setup for my component:
<script setup lang="ts">
interface FileMetadata {
owner: string,
location: string,
size: number,
// And around 50 mores...
}
interface File {
fileName: string,
metadata: FileMetadata
}
const file = defineModel<File>({ required: true });
const buildControls = (metadata: FileMetadata) => {
return [
{
label: 'Owner',
model: metadata.owner, // Is this correct?
type: 'text'
},
{
label: 'Location',
model: metadata.location, // Is this correct?
type: 'text'
},
{
label: 'Size',
model: metadata.size, // Is this correct?
type: 'number'
},
// And around 50 mores...
];
};
const controls = buildControls(file.value.metadata); // The value is already unpacked here
</script>
<template>
<div v-for=(item, idx) in controls>
<v-text-field v-model="item[idx].model" :label="item[idx].label" :type="item[idx].type" />
</div>
</template>
This component receives a File
object through its v-model
and displays a view for users to edit its metadata. Whenever the model changes (a different file is passed), the values of the text fields should update accordingly. Similarly, any changes made by users in the text fields should also reflect in the model. This behavior represents a two-way binding.
The view renders correctly, but I'm encountering an issue where I cannot alter the values in the text fields (they revert to their initial values when losing focus). I suspect this happens because the file
is already unpacked when the buildControls()
function is invoked, causing a loss of reactivity. However, if I refrain from unpacking it (by not accessing its .value
), I lose access to its metadata
attribute.
If I try to make controls
reactive by using
const controls = reactive(buildControls(file.value.metadata));
then I am able to modify the values in the text fields, but the file
model does not update accordingly.
In my understanding, the value of the model
key should be a Ref
object. However, I seem to be unable to achieve this.
One potential solution could involve storing only the key name of the FileMetadata
instead of the entire object in the model
key. This way, it can be accessed later in the template as file.metadata[item.model]
. Nevertheless, I find this approach less than ideal. Why shouldn't I be able to simply store an object instead?
What error have I made in this setup? How can I ensure the data maintains its reactivity as intended?