Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setter for computed property obtained from store in vue.js

Tags:

vue.js

vuex

I'd like to make two checkboxes which get value from store.js and send them to backend through a form:

<label>Notify me 
    <input type="checkbox" v-model="notification" value="notification" />       
</label>

<label>Email me 
    <input type="checkbox" v-model="email" value="email" />     
</label>

I get the values as a computed property:

computed: {
  BASE_URL () {
    return this.$store.state.BASE_URL;  
  }, 
  notification () {
    return this.$store.state.notification; 
  },

  email () {
    return this.$store.state.email; 
  }
}

The problem is that checking the checkboxes does not change the values in the store, and in addition to that I get this warning in the console, like:

vue.esm.js?65d7:479 [Vue warn]: Computed property "notification" was assigned to but it has no setter.

I know that one can define setter in computed property, as described in the vue.js docs, but I don't know how to do that when there are multiple values to set, like in my particular case.

So appreciate your help to fix this.

like image 788
Karlom Avatar asked Nov 15 '17 10:11

Karlom


1 Answers

To change Vuex state, you will need a mutation.

Provided you have a mutation setNotification for changing the notification state, you can configure the property in your component like this:

computed: {
    notification: {
        get() { return this.$store.state.notification; },
        set(value) { this.$store.commit('setNotification', value); },
    },
},

You can now bind to it with v-model="notification" as normal.

See Form Handling in the docs for more info.


Since this is a frequent thing that I do in my projects, I have written a helper function which generates the computed properties:

function mapStateTwoWay(...args) {
    const result = {};

    if (args.length === 1) {
        for (const prop of Object.keys(args[0])) {
            result[prop] = {
                get() { return this.$store.state[prop]; },
                set(value) { this.$store.commit(args[0][prop], value); },
            };
        }
    } else {
        for (const prop of Object.keys(args[1])) {
            result[prop] = {
                get() { return this.$store.state[args[0]][prop]; },
                set(value) { this.$store.commit(args[0] + '/' + args[1][prop], value); },
            };
        }
    }

    return result;
}

Use it like this:

computed: {
    ...mapStateTwoWay({
        notifications: 'setNotifications',
        email: 'setEmail',
    }),

    // Namespaced
    ...mapStateTwoWay('namespace', {
        notifications: 'setNotifications',
        email: 'setEmail',
    }),
}
like image 52
Decade Moon Avatar answered Sep 23 '22 06:09

Decade Moon