4

I am having troubles with how vuejs binds the data. I have a parent Vue.component which is the handles the layout of my form and i have child vue.component which handle the different input groups. I am having troubling getting the data from the child component to sync with the parent component for when i do my form submit in future.

I currently have my file like this:

var title = "";
Vue.component('create_new_entry', {
    template: '<div><div class="row"><h1 v-on:click="test()">{{title}}</h1><div class="col-md-12"><section_title></section_title></div></div></div>',
    data    : function() {
        return {
            title: title
        };
    },
});
Vue.component('section_title', {
    template: '<div><h1 v-on:click="test()">{{title}}</h1><input type="text" class="form-control" v-model="title"></div>',
    data    : function() {
        return {
            title: title
        };
    },
    methods : {
        test: function() {
            console.log(this);
        }
    }
});

I am not sure where i am going wrong and as much as i try to the documentation im still having trouble with how the data get bound and updated.

1 Answer 1

6

You are declaring two entirely separate fields, one in each component, and there is nothing tying them together other than they share the same name. Vue is treating those as two separate fields, when one changes, the other does not. The fields are private and internal to the component instances.

Shared state should be passed down to child components as props, and should be passed up to parent components as events. There are a few ways of approaching this, the simplest being adding a prop and event. A more complex way would be to use a state management tool like vuex. https://github.com/vuejs/vuex

Here is a simple example using a prop and an event.

Prop documentation: https://v2.vuejs.org/v2/guide/components.html#Props

Event documentation: https://v2.vuejs.org/v2/guide/components.html#Custom-Events

var title = "";
Vue.component('create_new_entry', {
    template: '<div><div class="row"><h1 v-on:click="test()">{{title}}</h1><div class="col-md-12"><section_title :title="title" @title-changed="changeTitle"></section_title></div></div></div>',
    data    : function() {
        return {
            title: title
        };
    },
    methods: {
        changeTitle(newTitle) {
            this.title = newTitle;
        }
    }
});
Vue.component('section_title', {
    template: '<div><h1 v-on:click="test()">{{title}}</h1><input type="text" class="form-control" v-model="innerTitle"></div>',
    props: ['title'],
    data    : function() {
        return {
            innerTitle: this.title
        };
    },
    methods : {
        test: function() {
            console.log(this);
        }
    },
    watch: {
        title(val){
            this.innerTitle = val;
        },
        innerTitle(val) {
            this.$emit('title-changed', val);
        }
    }
});

The parent component passes its title component down to the child component so it has access to it. The child component is unable to modify its props, so it copies the value of the prop to a local data field innerTitle. The input in the child component is bound to the innerTitle using v-model. A watch is added on the innerTitle so that any time it changes, it emits an event title-changed. The parent component listens for the title-changed event, and whenever it occurs, the parent updates its title field to that new value.

The child component also has a watch on the title prop so that if the parent's title value changes for any other reason, the child component will be able to update its internal state to match the parent's new value.

As stated before, you could also use Vuex, or use another Vue instance as a bus as explained here https://v2.vuejs.org/v2/guide/components.html#Non-Parent-Child-Communication

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you so much! This is really great explanations. I have seen other like this but never put as clearly as this so i never understood. Thank you

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.