Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue 3 pass reactive object to component with two way binding

I have an issue in the two way binding of a reactive component in vue 3 using the composition API.

The setup:

The parent calling code is:

<template>
  <h1>{{ message.test }}</h1>
  <Message v-model="message" />
</template>

<script>
import Message from '@/components/Message.vue';
import { reactive } from 'vue';

export default {
  name: 'Home',
  components: { Message },

  setup() {
    const message = reactive({ test: '123' });

    return {
      message
    };
  }
};
</script>

The child component code is:

<template>
  <label>
    <input v-model="message" type="text" />
  </label>
</template>

<script>
import { computed } from 'vue';

export default {
  props: {
    messageObj: {
      type: Object,
      default: () => {},
    },
  },

  emits: ['update:messageObj'],

  setup(props, { emit }) {
    const message = computed({
      get: () => props.messageObj.test,
      set: (value) => emit('update:messageObj', value),
    });

    return {
      message,
    };
  },
};
</script>

The problem:

When the component is loaded, the default value from the object is shown in the input field. This is as it should be, however, when I update the value in the input box the H1 in the parent view is not getting updated with the new input box value.

I have searched through the stackoverflow board and google but have not found any hint as to what needs to be done to make the object reactive.

I read through the reactivity documentation but still have not found any solution for my issue.

For testing I have changed message to be a ref and using this single ref value the data remains reactive and everything is working as expected.

Any pointers on what can be the issue with the reactive object not updating?

like image 494
Peter Pallen Avatar asked Nov 10 '20 19:11

Peter Pallen


People also ask

Does Vue support two-way data binding?

The v-model directive makes two-way binding between a form input and app state very easy to implement. One can bind a form input element and make it change the Vue data property when the content of the field changes.

Which Vue directive is used for two-way binding?

In Vue, two-way binding is accomplished using the v-model directive.

Is Vue one way or two-way binding?

Vue v-model is a directive that creates a two-way data binding between a value in our template and a value in our data properties.


1 Answers

Here

<div id="app">
    <h1>{{ message.test }}</h1>
    <child v-model="message"></child>
</div>
const { createApp, reactive, computed } = Vue;


// -------------------------------------------------------------- child
const child = {
    template: `<input v-model="message.test" type="text" />`,
    
    props: {
        modelValue: {
            type: Object,
            default: () => ({}),
        },
    },

    emits: ['update:modelValue'],

    setup(props, { emit }) {
        const message = computed({
            get: () => props.modelValue,
            set: (val) => emit('update:modelValue', val),
        });

        return { message };
    }
};


// ------------------------------------------------------------- parent
createApp({
    components: { child },

    setup() {
        const message = reactive({ test: 'Karamazov' });

        return { message };
    }
}).mount('#app');
like image 90
Matt Deacalion Avatar answered Oct 21 '22 05:10

Matt Deacalion