Search code examples
vuexv-for

how to mutate an array inside a v-for in vuex store?


I have a v-model inside a v-for. The v-model updates on the component but not in store/state. Im struggling to find a away round this. I have read various articles about vuex and arrays but I am struggling to apply the code to my problem. This is the first time I have really used vuex out in the wild, any help much appreciated.

selectedPassengerCount[i] is the part that I am trying to update

in the component I have

      <li v-for="(passengertype, i) in passengertypes" :key="i">
        <span>{{ passengertype.type }}</span>
        <div class="passenger-count__container">
          <button>-</button>
          <input type="number" min="1" v-model="selectedPassengerCount[i]" />
          <button>+</button>
        </div>
      </li>

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

    selectedPassengerCount: {
      get() {
        return this.$store.state.selectedPassengerCount;
      },
      set(value) {
        this.$store.commit("updateSelectedPassengerCount", value);
      },
    },
  },


and in the store I have


  state: {
    passengertypes: [
      {
        type: "a"
      },
      {
        type: "b"
      },
      {
        type: "c"
      }
    ],
     selectedPassengerCount: []
  }

  mutations: {
   updateSelectedPassengerCount(state, selectedPassengerCount) {
      state.selectedPassengerCount = selectedPassengerCount;
    },
  },

Solution

  • The problem with your code is in the fact that selectedPassengerCount setter would be called only when selectedPassengerCount is assigned new value (array).

    The v-model updates on the component but not in store/state

    I really doubt about this. Your code in fact mutates the array stored in Vuex directly (via v-model) without executing any mutation. You can check this by using Strict mode - when active, your code should throw an error in console....

    Way around it is to decompose v-model:

    <button @click.prevent="updatePassangerCount(i, selectedPassengerCount[i] - 1)"  :disabled="selectedPassengerCount[i] === 1"> - </button>
    <input type="number" min="1" :value="selectedPassengerCount[i]" @input="updatePassangerCount(i, $event.target.value)" />
    <button @click.prevent="updatePassangerCount(i, selectedPassengerCount[i] + 1)"> + </button>
    
    methods: {
      updatePassangerCount(index, value) {
        const newArray = [...this.selectedPassengerCount]
        newArray[index] = parseInt(value)  // value from input is always string
        this.$store.commit("updateSelectedPassengerCount", newArray); 
        // or create a new mutation with (index, value) arguments
      }
    }