Search code examples
vue.jsvuejs2vuex

Vuex - changing value based on component's current index and passing the value to other components


I have hit a wall and cannot get over it without your help now. I've spent a good few days trying to get my head around mutations and actions but this particular case I have doesn't seem to apply to tutorials online, also the answers on here are for different scenarios to mine. So here goes:

Setup: - Project is using vuex and store for data and state management - Currently App.vue has two child components: PizzaGenerator.vue and BaseButtons.vue

I am trying to achieve this: - When I click on a specific button in BaseButtons.vue I need a centrally managed showBaseIndex to be assigned an index value. This value is then available to the other, PizzaGenerator.vue, component which will reflect the change and show a layer that matches the new value of showBaseIndex.

Please see all the two components and store below.

Can you help me head in the right direction?

PizzaGenerator.vue

<template>
<div class="pizza-generator section" id="screen3" data-anchor="screenThree">
    <ul class="pizza-layers">
        <!-- Display pizzas -->
        <li v-for="(item, index) in getBase" class="pizza-canvas pizza-canvas--base" v-bind:class="item.class"  v-if="$store.state.showBaseIndex == index"></li>
        <!-- END Display pizzas -->
    </ul>

    <div class="pizza-items">
        <app-base-buttons></app-base-buttons>
    </div>
</div>
</template>

<script>
import Base from './pizza-buttons/BaseButtons'
import { mapGetters, mapActions } from 'vuex'

export default {
components: {
    appBaseButtons: Base
},
computed: {
    getBase(){
        return this.$store.state.base
    }
},
methods: mapActions([
    'baseLayer',
]),
}
</script>

BaseButtons.vue

   <div class="pizza-items-selector pizza-items-selector--dough">
    <div class="pizza-items-selector__items pizza-items-selector__items--dough">
        <div class="sliding-buttons">
            <button v-for="(item, index) in getBase" class="sliding-buttons__button dough-button" :key="index" @click="baseLayer = index"> {{ item.name }}</button>
        </div>
        <button class="buttons-prev-1 prev">prev</button>
        <button class="buttons-next-1 next">next</button>
    </div>
</div>

<script>
import { mapActions, mapMutations } from 'vuex'
export default {
computed:{ 
    getBase(){
        return this.$store.state.base
    },
},
methods:{ 
    ...mapMutations([
        'baseLayer',
    ]),
    baseLayerIndex() {
        this.$store.commit('baseLayer');
    }
},  

}

store.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export const store = new Vuex.Store({
state: {
    showBaseIndex: 1,
    base : [
        { name: 'Dünner Italienisch', class: 'pizza-canvas--base-italienisch', id: 1 },
        { name: 'Dünner Italienisch - Vollkorn', class: 'pizza-canvas--base-italienisch--vollkorn', id: 2 },
        { name: 'Dicker Amerikanisch', class: 'pizza-canvas--base-amerikanisch', id: 3 },
        { name: 'Dicker Amerikanisch / Chili-Käse-Rand', class: 'pizza-canvas--base-amerikanisch--chilli-kaese-rand', id: 4 },
        { name: 'Dicker Amerikanisch / Käse-Rand', class: 'pizza-canvas--base-amerikanisch--kaese-rand', id: 5 }
    ],
},
getters: {
    //
},
mutations: {
    baseLayer (state){
        state.showBaseIndex
    }
}, 
});
export default store;

Solution

  • Mutations are functions, not simple values. You should check the Vuex guide about mutations, they are quite straightforward.

    What you should do is declaring the given mutation in this way, so it will also accept a parameter:

    mutations: {
        baseLayer (state, id){
            state.showBaseIndex = id;
        }
    }, 
    

    and commit the mutation properly in the component:

        methods:{ 
        ...mapMutations([
            'baseLayer',
        ]),
        baseLayerIndex(index) { // call this at @click on button, giving the index as parameter
            this.$store.commit('baseLayer', index);
        }
        }
    

    This will set the desired index in the store, and from that on you could get the current base from store using vuex getters like:

    getters: {
        getSelectedBase(state){
          return state.base.find(base=>{return base.id === state.showBaseIndex});
        }
    },