2π
β
Every object should have it property isMark
as below:
UPDATE: you can merge properties to your original data after be fetched:
const myData = [
{ title: "one"},
{ title: "two" },
{ title: "three" },
{ title: "four" },
]
new Vue({
el: '#app',
data() {
return {
isLoading: true,
allBooks: []
}
},
created() {
this.fetchAPI()
},
methods: {
fetchAPI() {
setTimeout(() => {
this.allBooks = myData.map(item => ({...item, isMark: false }))
this.isLoading = false
}, 2000)
},
markAsFavorite(book) {
book.isMark = !book.isMark
}
}
})
.my-icon {
cursor: pointer;
margin-left: 4px;
}
.isActive {
color: red;
}
.flex {
display: flex;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.12.1/js/all.min.js"></script>
<div id="app">
<span v-if="isLoading">
loading
<i class="fas fa-spinner fa-spin"></i>
</span>
<template v-else>
<div class="flex" v-for="(book, index) in allBooks" :key="index">
<div>Title: {{ book.title }}</div>
<span
:class="[
{ isActive: book.isMark },
'my-icon'
]"
@click="markAsFavorite(book)"
>
<i class="fas fa-heart"></i>
</span>
</div>
</template>
</div>
1π
I would separate out each book into its own component. That way it can track its own isMark
Book.vue
<template>
<div>
<div>Title: {{ book.title }}</div>
<i @click="markAsFavorite" :class="{isActive: isMark}" class="fas fa-heart"></i>
</div>
</template>
<script>
export default {
name: 'Book',
props: { book: Object },
data: () => ({ isMark: false }),
methods: {
markAsFavorite () {
this.isMark = !this.isMark
this.$emit(this.isMark ? 'marked' : 'unmarked', this.book)
}
}
}
</script>
and then in your Books component
<template>
<v-flex v-for="(book, index) in allBooks" :key="index">
<Book :book="book" @marked="handleMarked" @unmarked="handleUnmarked" />
</v-flex>
</template>
<script>
import Book from './Book.vue'
export default {
name: 'Books',
components: { Book },
// and so on
}
</script>
π€Phil
Source:stackexchange.com