admin管理员组

文章数量:1287584

I have a model in TypeScript which has a map for translations as a property: Map<string, Translation> whereas the key is the language and the value the following interface:

interface Translation {
    title: string;
    description?: string;
}

In a modal, to which I pass the model via v-model, I render a fieldset for each entry:

<fieldset v-for="([language, translation]) in translationsRef">
    <legend>{{ language }}</legend>
    <p>
        <label for="title">Title </label>
        <input type="string" id="title" v-model="translation.title">
    </p>
    <p>
        <label for="description">Description </label>
        <textarea id="description" v-model="translation.description"></textarea>
    </p>
</fieldset>

My problem is that the whole thing is reactive, so as soon as I type something in the fields the model gets updated. I tried to use unref and toValue from vue, when I set the value from translationsRef but this seems to be shallow and not a deep unref of the map. Is there a method that I am missing or do I need to manually copy the values from the model into my ref?

For completeness here is how I implemented it at the moment. It is a bit too complex to have a working example ready:

const model = defineModel<Note|null>();

const translationsRef: Ref<Map<string, Translation>|null> = ref(null);

watch(model, (newNote) => {
    if (newNote != null) {
        translationsRef.value = toValue(newNote.translations);
        showModal.value = true;
    }
});

I have a model in TypeScript which has a map for translations as a property: Map<string, Translation> whereas the key is the language and the value the following interface:

interface Translation {
    title: string;
    description?: string;
}

In a modal, to which I pass the model via v-model, I render a fieldset for each entry:

<fieldset v-for="([language, translation]) in translationsRef">
    <legend>{{ language }}</legend>
    <p>
        <label for="title">Title </label>
        <input type="string" id="title" v-model="translation.title">
    </p>
    <p>
        <label for="description">Description </label>
        <textarea id="description" v-model="translation.description"></textarea>
    </p>
</fieldset>

My problem is that the whole thing is reactive, so as soon as I type something in the fields the model gets updated. I tried to use unref and toValue from vue, when I set the value from translationsRef but this seems to be shallow and not a deep unref of the map. Is there a method that I am missing or do I need to manually copy the values from the model into my ref?

For completeness here is how I implemented it at the moment. It is a bit too complex to have a working example ready:

const model = defineModel<Note|null>();

const translationsRef: Ref<Map<string, Translation>|null> = ref(null);

watch(model, (newNote) => {
    if (newNote != null) {
        translationsRef.value = toValue(newNote.translations);
        showModal.value = true;
    }
});
Share Improve this question asked Feb 23 at 16:22 ThomasThomas 7,1185 gold badges36 silver badges77 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

I found a similar question after I asked this one, but the solution doesn't work for Map: https://stackoverflow/a/78310852/3737177
But at leas it inspired me to write a typesave simple unref for maps (not nested, if needed it could probably be combined with the linked answer from Lucas David Ferrero).

import { unref } from 'vue';
export function unrefMap<T extends Object>(sourceMap: Map<string, T>): Map<string, T> {
    const plainMap = new Map<string, T>();
    sourceMap.forEach((value, key) => {
        const valueUnref: T = Object.keys(value).reduce((acc, key) => {
            acc[key as keyof typeof acc] = unref(value[key as keyof typeof acc]);
            return acc;
        }, {} as T);
        plainMap.set(unref(key), valueUnref);
    });
    return plainMap;
}

本文标签: vuejs3Is there something like a deep unref for VueStack Overflow