What if the model value of a Vue3 input doesn’t match what’s shown on screen?
Environment
- Vue 2.7
- Using the
<script setup>syntax
The Problem
I built an ordinary select box that receives the selected value through v-model. I wanted to implement business logic where selecting a certain option triggers a validation function, which displays a message and prevents that option from being selected.
But a problem arose. The validation function worked fine, and it blocked the change to v-model… yet on screen, the option I had just selected was still showing as selected. Since v-model wasn’t changed, shouldn’t the option value remain the one it was before the change?
When I looked inside the Vue instance, the v-model value had been changed exactly as I intended. But the select box bound to v-model was displaying the wrong value.
The Cause
- One-line summary: because v-model didn’t change, no rerender happened.
- A
selecttag’s value is a value provided by the HTML DOM API. - When you set an input’s value (here, the selected value) via Vue’s v-model, that is a value inside the Vue instance.
- Vue rerenders when a value inside the Vue instance changes.
- The HTML DOM API’s input value had already changed the moment the user selected it.
- But since the value inside the Vue instance didn’t change, no rerender happened.
- The input value set by Vue’s v-model and the input value from the DOM API ended up out of sync.
The Solution
There are several approaches, but changing the key is the cleanest way.
<template>
<MyComponent :key="componentKey" />
</template>
<script setup>
import { ref } from 'vue';
const componentKey = ref(0);
const forceRerender = () => {
componentKey.value += 1;
};
</script>
Don’t waste your time attempting weird hacks like $forceUpdate.
Leave a comment