JakeParis
JakeParis

Reputation: 11210

Vuex with components only update one way

Setup

I have a super-simple test app with two components (an <h1> and an <input>) and a vuex data store. The <input. is bound to the store data element pageTitle with v-model, and the <h1> displays pageTitle using double brackets. When I change the text in the input field, the value is changed in the store and all components (I can see that in the dev tools).

Problem

However, when I change the value in the store directly in the console (using store.state.pageTitle = 'something else', the <h1> updates, but the value in the text field does not. However, on initial page load, the input is correctly populated using the data from the store. I guess it's not receiving updates from the store.

Question

Why is my input field not receiving updates from the store and updating it's value?


Code

Javascript

const store = new Vuex.Store({
    state: {
        pageTitle: "My Vuex Thing"
    },
    mutations: {
        pageTitle(state,title){
            state.pageTitle = title;
        }
    }
});

const topsection = {
    template: `<h1>{{ pageTitle }}</h1>`,
    computed: {
        pageTitle(){
            return store.state.pageTitle;
        }
    }
};
const contentsection = {
    template: `<div id="content">
        Enter a page title: <input type="text" name="pageTitle" v-model="pageTitle">
    </div>
    `,
    computed: {
        pageTitle(){
            return store.state.pageTitle;
        }
    },
    watch: {
        pageTitle(val){
            store.commit('pageTitle',val);
        },
    }
};


var v = new Vue({
    el: '#vue',
    store,
    components: {
        topsection,
        contentsection
    }
});

HTML

<div id="vue">
    <topsection></topsection>
    <contentsection></contentsection>
</div><!-- #vue -->

Upvotes: 1

Views: 887

Answers (1)

Vamsi Krishna
Vamsi Krishna

Reputation: 31352

You are using v-model="pageTitle" where pageTitle is a computed property. Computed properties are by default getter-only, but you trying to bind the value by using v-model.

So what you need is a computed setter.

So your contentsection component should be like this:

const contentsection = {
    template: `<div id="content">
        Enter a page title: <input type="text" name="pageTitle" v-model="pageTitle">
    </div>
    `,
    computed: {
        pageTitle:{
            get: function(){
                return store.state.pageTitle;
            },
            set: function(newTitle){
                store.commit('pageTitle',newTitle);
            }
        }
    }
}; 

You do not need a watcher.

Here is the working jsFiddle

Upvotes: 1

Related Questions