'Making v-model:value lazy

I have a simple Vue component, which comes from a 3rd party package.

The component is a text editor, and I have to provide it with a value for it to render correctly.

<SomeComponent v-model:value="text" />

<script setup>
const props = {
    records: {
        type: Object,
    },
}
const text = computed(() => props.records.first())
</script>

Now, I want to update my database everytime the text property is changed.

watch(text, () => {
    //Post to database...
})

I don't, however, want to update the database on every keystroke - hence, I want to make the v-model lazy. This I am trying to do like this:

<SomeComponent v-model:value.lazy="text" />

However, this doesn't work. The code inside my watch method is being fired on every keystroke.



Solution 1:[1]

As shown in the documentation, v-model is just some sugar syntax.

So that those are the same

<input v-model="text">

<input :value="text" @input="event => text = event.target.value">

If you want to have your component updated on the change event, you could then use something like this

<SomeComponent :value="text" @change="event => text = event.target.value" />

Or this one rather

<SomeComponent v-model.lazy="text" /> <!-- text is the getter and the setter here -->

As shown in the documentation: https://vuejs.org/guide/essentials/forms.html#lazy


If you want something even more advanced, you could look into debouncing your inputs (more work but it's kinda more clever into handling when to update the state).

Solution 2:[2]

  1. You do not need to use v-model:value="text", just v-model="text" is enough.

  2. If you wanted the input to be lazy, without any extra functionality (like posting to DB on every change) then v-model.lazy="text" would be enough.

  3. When using watch, it doesn't matter whether your input is updated lazily or instantly. The watcher watches for each and every change, i.e: every keystroke in the case of an input.


So if you wish to make it lazy and make a call to DB on every change, then you need to this:

<SomeComponent :value="text" @change="onChange">\

<script setup>
   const onChange = (event) => {
     text.value = event.target.value;
     // post to DB
   }
</script>

If this doesn't work, then the suspect is the 3rd party package. In which case I suggest you look at the package's documentation and see if they provide a prop for the text editor to be lazy.

Solution 3:[3]

The 3rd party plugin did not allow me to omit the v-model:value property, so I ended up using lodash' debounce method instead:

<SomeComponent v-model:value.lazy="text" />
watch(text, _.debounce(function () {
    //Post to database...
}, 500));

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 kissu
Solution 2
Solution 3 oliverbj