My latest project involves creating a page that displays a variety of books, with the data being fetched from a backend API and presented as cards.
Each book card features two button sections: the first section includes "ADD TO BAG" and "WISHLIST" buttons (initially visible), while the second section contains a "ADDED TO BAG" button (initially hidden).
When a user clicks on the "ADD TO BAG" button on a specific card, it should hide both the "ADD TO BAG" and "WISHLIST" buttons and display the "ADDED TO BAG" button exclusively for that clicked card. I need assistance in applying styles only to the clicked card, while the remaining cards should remain unaffected.
This is how the default page looks before clicking on the "ADD TO BAG" button: https://i.sstatic.net/rwIqV.png
After clicking on the "ADD TO BAG" button, this is the output I currently get: https://i.sstatic.net/svVHf.png
DisplayBooks.vue
<template>
<div class="carddisplay-section">
<div v-for="book in books" :key="book.id" class="card book">
<div class="image-section">
<div class="image-container">
<img v-bind:src="book.file" />
</div>
</div>
<div class="title-section">
{{book.name}}
</div>
<div class="author-section">
by {{book.author}}
</div>
<div class="price-section">
Rs. {{book.price}}<label class="default">(2000)</label>
<button v-if="flag" class="btn-grp" type="submit" @click="handlesubmit();Togglebtn();">close</button>
</div>
<div class="buttons">
<!-- This is my button section -->
<div class="button-groups">
<button type="button" @click="toggle(book.id);toggleClass(book.id);" v-bind:class="[storeBooks.indexOf(book.id) >-1 ? 'red' : 'blue']" class="AddBag">Add to Bag</button>
<button class="wishlist">wishlist</button>
</div>
<!-- v-if="state==false" -->
<div v-bind:class="[!(storeBooks.indexOf(book.id)) >-1 ? 'blue':'red']" @click="toggle(book.id)" class="AddedBag">
<button class="big-btn">Added to Bag</button>
</div>
</div>
</div>
<!-- <Cart :cardId="clickedCard" v-if="false" /> -->
</div>
</template>
<script>
import service from '../service/User'
export default {
data() {
return {
isActive:true,
storeBooks:[],
result: 0,
authorPrefix: 'by',
pricePrefix: 'Rs.',
defaultStrikePrice: '(2000)',
buttonValue: 'close',
flag: true,
state: true,
clickedCard: '',
books: [{
id: 0,
file: 'https://images-na.ssl-images-amazon.com/images/I/41MdP5Tn0wL._SX258_BO1,204,203,200_.jpg',
name: 'Dont Make me think',
author: 'Sai',
price: '1500'
}, ]
}
},
methods: {
toggleClass: function(event){
this.isActive = !this.isActive;
return event;
},
toggle (id) {
this.clickedCard = id;
const index = this.storeBooks.indexOf(id);
if(index > -1) {this.storeBooks = this.storeBooks.splice(index,1)}
else{
this.storeBooks.add(id)
}},
flip() {
this.state = !this.state;
},
Togglebtn() {
this.flag = !this.flag;
},
handlesubmit() {
service.userDisplayBooks().then(response => {
this.books.push(...response.data);
})
},
}
}
</script>
<style lang="scss" scoped>
@import "@/styles/DisplayBooks.scss";
</style>
Following the update to the component code, here is the current output: https://i.sstatic.net/Goc5L.png However, my expected outcome can be seen here: [what I need is]3
DisplayBooks.scss
@import "colors";
.carddisplay-section {
display: flex;
align-items: flex-start;
flex-wrap: wrap;
align-content: space-around;
gap: 10px;
}
.card:hover{
box-shadow:0.6px 0.6px 0.6px 0.6px rgb(173, 206, 206);
}
.card {
margin-top: 55px;
margin-left: 110px;
background:$pink;
width: 235px;
height: 315px;
background: $pale_white 0% 0% no-repeat padding-box;
border: 1px solid $border_clr;
border-radius: 3px;
opacity: 1;
}
.image-section {
width: 233px;
height: 172px;
background: #F5F5F5 0% 0% no-repeat padding-box;
border-radius: 2px 2px 0px 0px;
opacity: 1;
}
img{
margin-left: 67px;
margin-top: 17px;
width: 105px;
height: 135px;
opacity: 1;
border:none;
}
.title-section {
text-align: left;
font: normal normal normal 14px/19px Roboto;
letter-spacing: 0.2px;
color: $light_black;
opacity: 1;
margin-left: 20px;
margin-top: 3px;
width: 130px;
height: 19px;
text-transform: capitalize;
}
.author-section {
text-align: left;
font: normal normal normal 13px/13px Roboto;
letter-spacing: 0px;
color: $light_grey;
opacity: 1;
width: 123px;
height: 13px;
margin-left: 20px;
margin-top: 7px;
}
.price-section {
text-align: left;
font: normal normal bold 12px/16px Roboto;
letter-spacing: 0px;
color: $light_black;
opacity: 1;
margin-left: 20px;
height: 16px;
margin-top: 26px;
display: flex;
justify-content: flex-start;
}
label {
text-decoration-line: line-through;
font: normal normal normal 10px/13px Roboto;
letter-spacing: 0px;
color: $light_grey;
opacity: 1;
width: 36px;
height: 13px;
margin-top: 2.5px;
margin-left: 1em;
}
button[type="submit"] {
border: none;
padding-left: 65px;
background: none;
font-size: 15;
}
.button-groups{
display:flex;
margin-top:8px;
}
.AddBag{
background: #A03037 0% 0% no-repeat padding-box;
border-radius: 2px;
opacity: 1;
width: 93px;
height: 29px;
margin-left:20px;
color: #FFFFFF;
text-transform: uppercase;
opacity: 1;
font-size: small;
}
.wishlist{
margin-left:4px;
color: #FFFFFF;
text-transform: uppercase;
opacity: 1;
font-size: small;
border: 1px solid #7c7a7a;
border-radius: 2px;
opacity: 1;
color: #0A0102;
width:93px;
}
.big-btn{
width: 191px;
height: 29px;
margin-left:20px;
background: #3371B5 0% 0% no-repeat padding-box;
border-radius: 2px;
opacity: 1;
color:#FFFFFF;
}
.red{
background: red;
}
.blue{
background: yellow;
display:none;
}