Adding option to cart increments all counters

Viewed 86

When I add an option to the cart, the counters of all the options increase at the same time. I tried with Vuex, but I'm inexperienced with it, so I took a simpler approach. How can I add an option without all the counters increasing?

(I put together an example of the code, so that it's easier to explain.)

<template>
    <div>
         <div v-for="optionTests in ArrayOption" :key="optionTests.id">
            <p>{{ optionTests.id}}</p>
            <p>{{ optionTests.name}}</p>
            <p>{{ optionTests.description}}</p>
            <button  @click="testCount -= 1" :disabled="testCount < 1">-</button>
            <p>{{ testCount }}</p>
            <button @click="testCount += 1" :disabled="testCount > 0">+</button>
        </div>
    </div> 
</template>
 
<script>
import axios from 'axios'
 
export default {
    data(){
        return{
            ArrayOption:[
                {
                    id:1,
                    name: 'option1'
                    description: 'je suis l option 1 ajoute moi au panier'
                },
                {
                    id:2,
                    name: 'option2'
                    description: 'je suis l option 2 ajoute moi au panier'
                },
                {
                    id:3,
                    name: 'option3'
                    description: 'je suis l option 3 ajoute moi au panier'
                },
                {
                    id:4,
                    name: 'option4'
                    description: 'je suis l option 4 ajoute moi au panier'
                }
            ],
            testCount:0,
        }
    }
}

enter image description here

1 Answers

What's going on here is that, while you're rendering a unique card for each option in your array, your counters are all hooked up to the same variable in data.

This means that when you change one counter, all the counters will update to show the new total, because they're all really showing the same number under the surface, even though they appear in different places.

To solve this, you'll need to store the option counts separately, so they can be read and iterated separately.


Here's one way you could go about doing this.

Instead of displaying and manipulating testCount directly, you could store each option counter as a key in a counter object, so that each can be incremented or decremented on their own:

testCounter: { 
  "option1": 0, 
  "option2": 0,
  "option3": 0,
  "option4": 0 
}

Here's an interactive example showing this off!

Note that I had to use a special Vue instance method, vm.$set(), to make the individual counters reactive. Vue can't track when you dynamically create new properties in an object, so we have to tell Vue explicitly to add a new key for us, using vm.$set([object], [key name], [initial value]).

new Vue({
  el: '#app',
  data() {
    return {
      arrayOption: [{
          id: 1,
          name: 'option1',
          description: 'je suis l option 1 ajoute moi au panier'
        },
        {
          id: 2,
          name: 'option2',
          description: 'je suis l option 2 ajoute moi au panier'
        },
        {
          id: 3,
          name: 'option3',
          description: 'je suis l option 3 ajoute moi au panier'
        },
        {
          id: 4,
          name: 'option4',
          description: 'je suis l option 4 ajoute moi au panier'
        }
      ],
      testCount: {},
    }
  },
  created() {
    // Important setup step–
    //  this.$set makes the counter properties reactive
    //  so that the DOM updates when you click a counter
    this.arrayOption.forEach(op => this.$set(this.testCount, op.name, 0));
  },
});
.card {
  background: #bbc0c4;
  border: solid;
  padding: 5px;
  margin: 5px;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-content: space-around;
  justify-content: space-around;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
  <div>
    <p>Values: {{ testCount }}</p>
    <div v-for="optionTest in arrayOption" :key="optionTest.id" class="card">
      <p>{{ optionTest.id }}</p>
      <p>{{ optionTest.name }}</p>
      <p>{{ optionTest.description }}</p>
      <button @click="testCount[optionTest.name] -= 1" :disabled="testCount[optionTest.name] < 1">-</button>
      <p>{{ testCount[optionTest.name] }}</p>
      <button @click="testCount[optionTest.name] += 1" :disabled="testCount[optionTest.name] > 0">+</button>
    </div>
  </div>
</div>

Related