Search code examples
javascriptvue.jsvuejs2vue-componentv-for

Bind class if a dynamic variable is true [all in v-for]


Sorry for my code but I'm new with Vue.

I have 5 span items like this [span with :class]

              <span class="bars">
                <span class="bar" :class="{ selected1: isActive[0] }"></span>
                <span class="bar" :class="{ selected2: isActive[1] }"></span>
                <span class="bar" :class="{ selected3: isActive[2] }"></span>
                <span class="bar" :class="{ selected4: isActive[3] }"></span>
                <span class="bar" :class="{ selected5: isActive[4] }"></span>
              </span>

These match to 5 grey circles. The classes 'selected1, selected, ...' fill the circles with 5 different colors. "isActive" is an array of 5 boolean variables [false, false, false, false, false]. To change the statement of these boolean variables I use a function that fires every time I get data from Firebase.

  data() {
    return {
      isActive: [], // boolean array
      ricettario: [] // array of firebase data
    };
  },

So when isActive[0] is true the span becomes filled, when isActive1 is true the span becomes filled, etc...

The function I use is named "setDiff" which picks the data from Firebase Database and puts it to a switch statement.

// Firebase get data
created() {
    db.collection("ricettarioFirebase")
      .get()
      .then(snapshot => {
        snapshot.forEach(doc => {
          let ricetta = doc.data();
          ricetta.data = dayjs(ricetta.data) // time
            .locale("it") // time
            .format("D MMMM YYYY"); // time
            this.setDiff(ricetta.diff); // diff = "molto facile || facile || ..."
          this.ricettario.push(ricetta); // push data to ricettario[]
        });
      });
  }


// Function that change isActive[]
  methods: {
    setDiff(diff) {
      switch (diff) {
        case "molto facile":
          i = 1;
          for (j = 0; j < i; j++) {
            this.isActive[j] = true; // only one filled span
          }
          break;
        case "facile":
          i = 2;
          for (j = 0; j < i; j++) {
            this.isActive[j] = true; // 2 filled span
          }
          break;
        case "medio":
          i = 3;
          for (j = 0; j < i; j++) {
            this.isActive[j] = true; // 3 filled span
          }
          break;
        case "difficile":
          i = 4;
          for (j = 0; j < i; j++) {
            this.isActive[j] = true; // 4 filled span
          }
          break;
        case "molto difficile":
          i = 5;
          for (j = 0; j < i; j++) {
            this.isActive[j] = true; // 5 filled span
          }
          break;
      }
    }
  }

The problem is that the DOM receives only the last statement, so every card created with v-for has the same span color. I would like to have the card with different filled span. The following image shows the problem. problem


Solution

  • You have one global variable isActive[]

    You are fetching an array of objects from the database.

    Then you are calling setDiff(someString) for each of the retrieved object. Each time you call the function you essentially override the values set by the previous call.

    You could make isActive a two dimensional array (for example isActive[item.id][0]) or attach isActive to ricetta before pushing it to ricettario array

    ricetta.isActive = this.setDiff(ricetta.diff); // remember to return isActive from setDiff function
    ricettario.push(ricetta)
    

    For this problem you could even use simple CSS and a :class from ricetta.diff

    https://codepen.io/szkuwa/pen/JjdNYov