Skip to content Skip to sidebar Skip to footer

Vue .sync Only Works With V-model, But Gives Mutation Error

// NOTE: Issue was due to VueFormulate's FormulaInput (custom input). Check the code sandbox for 3 working examples of .sync Usecase My app is injecting multiple dynamic componen

Solution 1:

The reason value didn't work is only because you are emitting the same unchanged value which is passed down. Without v-model, nothing changes value, so there was nothing new to emit back up.

Change that input to:

<input
  :value="value"
  @input="$emit('update:value', $event.target.value)"
  type="text"
  step="1"
  placeholder="Child Input1 (value)"
/>

This way, when the input event happens, you emit a new value from the input box.


Solution 2:

For completeness, I'd like to add to Dan's answer a generic alternative: a Vue pattern that allows using v-model with anything that can't be directly mutated: computed getter + setter.

Proof of concept:

Vue.component('child', {
  template: `
  <input v-model="local" type="text" />
  `,
  props: ['value'],
  computed: {
    local: {
      get() {
        return this.value;
      },
      set(value) {
        this.$emit('update:value', value);
      }
    }
  }
})

new Vue({
  el: '#app',
  data: () => ({
    foo: {
      bar: 'baz'
    }
  })
})
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>

<div id="app">
  <div>
    <child :value.sync="foo.bar" />
  </div>
  <pre v-html="foo" />
</div>

I purposefully used a nested property, which is not normally reactive.

While using it in this particular example is really just a little more verbose (so it's probably less useful than Dan's proposed syntax) it can come in handy when used with Vuex state properties (get the store value in the getter and commit the mutation in the setter - especially since you can name the local computed the same as the state property).

Notably, it does not need an extra listener (which is a negligible performance increase) (e.g: @input, @change, @keydown, etc... - for completeness, in production code you might want to add in paste event listener and there might be other edge cases - autocomplete!? - although most cases are covered by @input, though).

The code in the setter gets run once every time there is a change in value for the v-model property, as you'd expect. In short, it's a proper two-way binding.


Post a Comment for "Vue .sync Only Works With V-model, But Gives Mutation Error"