Search code examples
javascriptvue.jsvuexvuetify.js

Change state using Mutation VueJS?


So i have a Vuex Store setup which returns me headers and desserts. Inside my desserts i have a property setup named display which is initially false. I have a component Row which i am importing inside my parent component named Table. Row Components accepts a couple of props i.e. Name and Display. The display prop is what is returned from desserts from the vuex store. I am trying to add a mutation such that on Click of the icon in my Row component, the display.laptop can be toggled to true and false. I have setup the toggleLaptopDisplay but i keep getting cannot read property laptop of undefined.

Please look at the complete CodeSandbox.

Here is the complete code:

The Vuex Store:-

export default new Vuex.Store({
  state: {
    headers: [{ text: "Dessert (100g serving)", value: "name" }],
    desserts: [
      { name: "Lollipop", display: { laptop: true } },
      { name: "Marshamallow", display: { laptop: false } }
    ]
  },
  getters: {
    getHeaders: state => state.headers,
    getDesserts: state => state.desserts
  },
  mutations: {
    toggleLaptopDisplay(state) {
      state.desserts.display.laptop = !state.desserts.display.laptop;
    }
  }
});

This is the Table Component:-

<template>
  <v-data-table :headers="getHeaders" :items="getDesserts" hide-actions select-all item-key="name">
    <template v-slot:headers="props">
      <tr>
        <th v-for="header in props.headers" :key="header.text">{{ header.text }}</th>
      </tr>
    </template>
    <template v-slot:items="props">
      <tr>
        <Row :name="props.item.name" :display="props.item.display"/>
      </tr>
    </template>
  </v-data-table>
</template>

<script>
import { mapGetters } from "vuex";
import Row from "./Row";
export default {
  components: {
    Row
  },
  data() {
    return {};
  },
  computed: {
    ...mapGetters({
      getHeaders: "getHeaders",
      getDesserts: "getDesserts"
    })
  }
};
</script>

This is the Row component:-

<template>
  <div>
    {{name}}
    <v-icon @click="toggleLaptopDisplay" :color="display.laptop ? 'info': '' ">smartphone</v-icon>
  </div>
</template>

<script>
import { mapMutations } from "vuex";
export default {
  props: {
    name: String,
    display: Object
  },
  methods: {
    ...mapMutations({
      toggleLaptopDisplay: "toggleLaptopDisplay"
    })
  }
};
</script>

Any help will be appreciated. Thank you :)


Solution

  • Few things to achieve what you want:

    In your Row.vue add a method to select appropriate element:

    <v-icon @click="toggleChange" :color="display.laptop ? 'info': '' ">smartphone</v-icon>
    

    then in methods, create a method that will pass name of the element as payload:

    methods: {
        toggleChange() {
            this.toggleLaptopDisplay(this.name)
          },
        ...mapMutations({
          toggleLaptopDisplay: "toggleLaptopDisplay"
        })
      }
    

    finally, in store.js, use the payload and mutate selected element:

    mutations: {
        toggleLaptopDisplay(state, payload) {
          state.desserts.find(dessert => dessert.name === payload).display.laptop = !state.desserts.find(dessert => dessert.name === payload).display.laptop
        }
      }
    

    Edited Example