Home > front end >  Vue not triggering changes inside v-if in template when using index
Vue not triggering changes inside v-if in template when using index

Time:12-21

I have some items and each item has a description with a show more link at the end. On this link's click, I want to trigger a function.
However, the method triggers correctly and prints the result in the console but the updates do not trigger in the Vue template.

Here is the complete code:

   <template>
    <main>
      <div  v-for="(item, index) in items" :key="index">
     
        <div >
          <h3 >{{item.name}} </h3>
          <p v-if="showMoreText[index]">{{ item.description }}</p>
            <p v-else>{{ item.description.substring(0, 100) }}...<span  @click="showMore(index)">show more</span></p>
        </div>
      </div>
    </main>
  </template>

<script>
export default {
    data() {
        return {
            showMoreText: []
        }
    },
    props: {
        items: Array,
    },
    created() {
  for (let i = 0; i < this.items.length; i  ) {
    this.showMoreText[i] = false;
  }
},
    methods: {
        showMore(index) {  
            this.showMoreText[index] = !this.showMoreText[index]
            // console.log(this.showMoreText[index])
                }
    },
}
</script>

CodePudding user response:

You are facing this problem because your data is not reactive.

According to the documentation-

Vue cannot detect the following changes to an array:

  1. When you directly set an item with the index, e.g. vm.items[indexOfItem] = newValue
  2. When you modify the length of the array, e.g. vm.items.length = newLength

The problem you are facing is the first case and to resolve it, you need to make the data reactive using Vue.set method-

// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// You can also use the vm.$set instance method, which is an alias to the global Vue.set:
this.$set(vm.items, indexOfItem, newValue)

Here's the working demo of your problem-

.link {
  color: blue;
  cursor: pointer;
}
<html>
<div id="app">
  <div  v-for="(item, index) in items" :key="index">
      <div >
        <h3 >{{ item.name }}</h3>
        <p v-if="showMoreText[index]">{{ item.description }}</p>
        <p v-else>
          {{ item.description.substring(0, 10) }}...<span
            @click="showMore(index)"
            ><span >show more</span></span
          >
        </p>
      </div>
    </div>
</div>

<!-- Don't forget to include Vue from CDN! -->
<script src="https://unpkg.com/vue@2"></script>
<script>
new Vue({
  el: "#app", //Tells Vue to render in HTML element with id "app"
  data() {
    return {
      showMoreText: [],
      items: [
        {
          name: "name1",
          description:
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
        },
        {
          name: "name2",
          description:
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
        },
        {
          name: "name3",
          description:
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
        },
        {
          name: "name4",
          description:
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
        },
      ],
    };
  },
  mounted() {
    for (let i = 0; i < this.items.length; i  ) {
      this.showMoreText[i] = false;
    }
  },

  methods: {
    showMore(index) {
      this.$set(this.showMoreText, index, !this.showMoreText[index]);
    },
  },
});
</script>
</html>

  • Related