Search code examples
vue.jsvuejs3

Is there a way to know whether a prop is v-model'd or one-way bound?


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.


Solution

  • 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.