Jiseung Roh
Jiseung Roh

Reputation: 221

VueJS v-if = array[index] is not working

I wanted to make a component which gets text-box when mouse is over the image.

Below is HTML template.

<section class="item-container" v-for="(item, index) in items">
  <div class="image-box" @mouseenter="changeStatus(index)">
    <img class="image" src="item.link" alt>
  </div>
  <div class="text-box" @mouseleave="changeStatus(index)" v-if="show[index]">
    <h4>{{ item.name }}</h4>
    <p>{{ item.content }}</p>
  </div>
</section>

And below is app.js

new Vue({
  el: '#app',
  data: {
    show: [false, false, false],
    items: [
      {
        name: 'Author 1',
        content: 'Content 1'
      },
      {
        name: 'Author 2',
        content: 'Content 2'
      },
      {
        name: 'Author 3',
        content: 'Content 3'
      }
    ]
  },
  methods: {
    changeStatus: function(index) {
      this.show[index] = !this.show[index];
      console.log(this.show); 
      console.log(this.show[index]);  // console gets it as expected
    }
  }
});

When I execute above codes, I can find that the show property has changed. However, v-if is not updated. Can't we use array[index] for v-if or is there other reason for it?

Upvotes: 22

Views: 15332

Answers (3)

devugur
devugur

Reputation: 1499

In component in methods you can use:

this.$set(this.show, index, !this.show[index])

Upvotes: 3

Igor de Lorenzi
Igor de Lorenzi

Reputation: 583

You can use a JS object instead of an array and get the same effect. In other words, replace show: [false, false, false], with show: {0:false, 1:false, 2:false},.

Upvotes: 3

CodinCat
CodinCat

Reputation: 15914

The problem is not about v-if, it's because Vue cannot detect the changes of an array element directly, this is one of the limitation of JavaScript.

Thus, Vue provides some helper functions for this, like Vue.set

Change this this.show[index] = !this.show[index]

to Vue.set(this.show, index, !this.show[index])

then it should work.

Vue.set is not the only solution, there are several ways to accomplish this, in case you may want to know.

You can use native methods of JavaScript array, Vue will hook on these methods so it can detect the changes.

Here is the example of the usage of .splice

this.show.splice(index, 1, !this.show[index])

Another way is to replace the array entirely. If you are using ES6, you can use the spread operator to clone the array easily:

this.show[index] = !this.show[index]
this.show = [...this.show]

.map will also work because it returns a new array

this.show = this.show.map((el, i) =>
  i === index ? !el : el
)

Upvotes: 37

Related Questions