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:
- 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
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>