Skoota
Skoota

Reputation: 5290

Bind class in Vue.js based upon array of booleans

I have a series of text fields with a button next to each field. When the user taps the button next to one of the fields I want to apply a particular style to that button (to change its colour) - essentially allowing the user to "tick" that they have checked that field (similar to a checklist).

There are nine text fields/buttons on the page, and I have the status of all the buttons stored in an array called items_checked which is initialized in data() as the following:

items_checked: [false, false, false, false, false, false, false, false, false]

Each button has the following code:

 <button class="btn btn-danger" v-on:click="toggleChecked(0)" v-bind:class="{'itemChecked' : items_checked[0]}">

where the number indicates the index of the button (i.e. 0 is the first button, 1 is the second button, etc.) to correspond to the equivalent boolean in items_checked.

The v-on:click event just toggles the checked status in the items_checked for the tapped button:

toggleChecked (itemIndex) {
  if (this.items_checked[itemIndex] === false) {
    this.items_checked[itemIndex] = true
  } else {
    this.items_checked[itemIndex] = false
  }
  console.log(this.items_checked)
}

This works as the console.log shows the boolean values toggling.

However, the v-bind does not work as the itemChecked class does not get applied to the button. It seems to be an issue binding to a boolean value within an array, as when I bind just to a standard boolean declared within data() it works fine.

I do eventually need all the checked statuses stored in an array, so that I can evaluate that all have been checked before allowing the user to submit the page.

Any help would be appreciated.

Upvotes: 2

Views: 1055

Answers (1)

ittus
ittus

Reputation: 22403

This is common reactivity problem.

In document:

Due to limitations in JavaScript, Vue cannot detect the following changes to an array:

When you directly set an item with the index, e.g. vm.items[indexOfItem] = newValue

When you modify the length of the array, e.g. vm.items.length = newLength

You can use deep copy

toggleChecked (itemIndex) {
  this.items_checked[itemIndex] = !this.items_checked[itemIndex]
  this.items_checked = JSON.parse(JSON.stringify(this.items_checked))
  console.log(this.items_checked)
}

Another solution is using Vue.set

toggleChecked (itemIndex) {
  var oldValue = this.items_checked[itemIndex]
  this.$set(this.items_checked, itemIndex, !oldValue)
  console.log(this.items_checked)
}

Upvotes: 2

Related Questions