Consider the following component
// <optional-select>
<script setup>
import { computed } from "vue"
const dropdownValue = defineModel("dropdown-value")
const dropdownIsModelBound = computed(() => {
// Logic goes here...
})
</script>
<template>
<select v-if="dropdownIsModelBound" v-model="dropdownValue">
<option>Option 1</option>
<option>Option 2</option>
</select>
<div v-else>{{dropdownValue}}</div>
</template>
What I'm trying to do is when the parent's like this:
<optional-select v-model:dropdown-value="x">
...<optional-select>
would render the dropdown, meanwhile if I do this:
<optional-select :dropdown-value="x">
...it would only render the div.
There is no reliable way and no need to do this. v-model
is sugar syntax for:
<optional-select :dropdown-value="x" @update:dropdown-value="x = $event">
Since event listener is translated to on...
prop on vnode object, it may be possible to detect it by accessing vnode.props['onUpdate:dropdownValue']
. But for the way a component works, it should make no difference whether event listener is provided.
By default v-model
prop is modelValue
. If a component works with a single value, it doesn't need a long custom prop name. It can use default prop name, which would make v-model
usage shorter and allow to use a different prop name for one-way binding, e.g. value
. So these uses behave differently:
<optional-select :model-value="x"/>
<optional-select :value="x"/>
Alternatively, use separate boolean prop like readonly
instead of dropdownIsModelBound
condition for cleaner and more predictable component API.