Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

vue.js

vuejs2

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?

like image 910
Jiseung Roh Avatar asked Jan 11 '17 00:01

Jiseung Roh


3 Answers

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},.

like image 29
Igor de Lorenzi Avatar answered Nov 08 '22 04:11

Igor de Lorenzi


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
)
like image 114
CodinCat Avatar answered Nov 08 '22 05:11

CodinCat


In component in methods you can use:

this.$set(this.show, index, !this.show[index])
like image 2
devugur Avatar answered Nov 08 '22 05:11

devugur