[Vuejs]-Changes applied to v-model does not trigger writable computed methods

1👍

TL,DR; Two issues need addressing to make your code work:

  • you haven’t declared vModelTimeSeriesAgo as a prop
  • it’s not clear why you’re using type="radio".

A. Declare the prop

In order for v-model:something="whatever" to work, you need to declare something as a prop and the emit in the child component. 1

parent

<some-child v-model:something="whatever" />

some-child

export default {
  props: ['something'], 
  emits: ['update:something']
}
<input :value="something" @input="$emit('update:something', $event.target.value)" />

Alternatively, you can define a local computed in child:

import { emit } from 'vue'
export default {
  props: ['something'],
  emits: ['update:something'],
  computed: {
    localSomething: {
      get() { return this.something },
      set(val) { emit('update:something', val)
    }
  }
}

or

export default {
  props: ['something'],
  emits: ['update:something'],
  setup(props, { emit }) {
    const localSomething = computed({
      get() { return props.something },
      set(val) { emit('update:something', val) }
    })
    return { localSomething }
  }
}

or

<script setup>
const props = defineProps(['something'])
const emit = defineEmits(['update:something'])
const localSomething = computed({
  get() { return props.something },
  set(val) { emit('update:something', val) }
})
</script>

and use with v-model:

<input v-model="localSomething" />

Now changing the input value in child component will update the parent whatever.


1 – The implicit v-model variable name is modelValue (when used as <some-child v-model="whatever" />. But you still need to declare the prop and the emit:

//...
  props: ['modelValue'],
  emits: ['update:modelValue']

B. Why are you using type="radio"?

All of the above apply to <input type="text" />. At this point, it’s not clear to me why you’re using type="radio" with only one option.

Radio buttons are typically used with multiple input elements all sharing the same v-model, each having a different value. When one of them is clicked, the v-model gets the value from that input and the previously selected radio inputs from the same group get unselected.

In the above example, using Options API, a child component would look something like this:

<script>
export default {
  data: () => ({
    values: ['One', 'Two', 'Three']
  }),
  props: ['something'],
  emits: ['update:something'],
  computed: {
    localSomething: {
      get() {
        return this.something
      },
      set(val) {
        this.$emit('update:something', val)
      }
    }
  }
}
</script>
<template>
  <label v-for="item in values" :key="item">
    <input v-model="localSomething" type="radio" :value="item" />{{ item }}
  </label>
</template>

Demo. And same, in <script setup>.

Leave a comment