I know this will need a refactor later to separate things out into their own components, but I'm up against a time crunch at the moment and need to wire this up as is. I used array.map() to create card elements from a JSON object I'm using for testing purposes. I'm attempting to use an onClick function on a card <div>
to save some identifiable information like 'offerid' into the component state and then check if the id in state matches the current card. If it matches, I want to add cardActive as the className on the div so that only that specific card changes color. I'm not sure how to do this. As it is now, all card stylings are updated no matter which card is selected. My React component and corresponding CSS are listed below. Any help would be hugely appreciated
React
import React, { Component } from 'react';
import Grid from '@material-ui/core/Grid';
import './Button.css';
class UsersList extends Component {
constructor(){
super();
this.state = {
cardActive: false,
customers:
[
{
"CustomerId": "1",
"LastName": "Doe",
"FirstName": "Jane",
"Address": {
"Address1": "1811 Chestnut Street",
"Address2": null,
"City": "Philadelphia",
"State": "Pennsylvania",
"Zip": "19103"
},
"Offers": [
{
"OfferId": "Offer1",
"Name": "Offer 1",
"Products": [
{
"ProductId": 1,
"ProductName": "Stuff"
},
{
"ProductId": 2,
"ProductName": "More stuff"
}
],
"Price": "$1"
},
{
"OfferId": "Offer2",
"Name": "Offer 2",
"Price": "$2",
"Products": [
{
"ProductId": 3,
"ProductName": "A lot of stuff"
},
{
"ProductId": 4,
"ProductName": "And then there was stuff"
}
]
},
{
"OfferId": "Offer3",
"Name": "Offer 3",
"Price": "$3",
"Products": [
{
"ProductId": 5,
"ProductName": "Good grief would you look at all this stuff"
},
{
"ProductId": 5,
"ProductName": "What a great deal for stuff"
}
]
}
]
}
]
}
}
selectCard(){
this.setState({ cardActive: !this.state.cardActive })
}
render (){
let card_class = this.state.cardActive ? "cardActive" : "card";
return (
<div>
{this.state.customers.map((customer, index) => {
return <div key={index + customer.CustomerId}>
<h2>Customer</h2>
<hr></hr>
<h3 >Name: {customer.LastName}, {customer.FirstName}</h3>
<h3 >Customer ID: {customer.CustomerId}</h3>
<h3 >
Address:
<br></br>
{customer.Address.Address1}
<br></br>
{customer.Address.City}, {customer.Address.State} {customer.Address.Zip}
</h3>
<br></br>
<h2>Available Offers</h2>
<Grid container spacing={24} justify="center">
{customer.Offers.map((Offer,index) => {
return <div key={index + Offer.OfferId} onClick={this.selectCard.bind(this)}>
<Grid item xs={12}>
<div className="card" class={card_class}>
<div className="container">
<h5><b>{Offer.OfferId}</b></h5>
<h2>{Offer.Name}</h2>
{Offer.Products.map((Product, index) => {
return <div key={index + Product.ProductId}>
<p>+ {Product.ProductName}</p>
</div>
})}
<h3>{Offer.Price}</h3>
</div>
</div>
</Grid>
</div>
})}
</Grid>
</div>
})}
<button className="navbuttonSelected">Submit</button>
</div>
)
}
}
export default UsersList
CSS
.card {
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
transition: 0.3s;
border-radius: 5px; /* 5px rounded corners */
margin-left: 70px;
margin-right: 70px;
margin-bottom: 5%;
cursor: pointer;
}
.cardActive {
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
transition: 0.01s;
border-radius: 5px; /* 5px rounded corners */
margin-left: 70px;
margin-right: 70px;
margin-bottom: 5%;
background: #0c72c5 !important;
color: white !important;
cursor: pointer;
}
.cardActive:hover {
box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2);
}
.card:hover {
box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2);
}
Set id of selected card:
selectCard(offerId) {
this.setState({ cardActive: offerId });
}
change how onClick
is called and apply specific class when Offer.OfferId === this.state.cardActive
return (
<div
key={index + Offer.OfferId}
onClick={() => this.selectCard(Offer.OfferId)}
>
<Grid item xs={12}>
<div
className={Offer.OfferId === this.state.cardActive ? "cardActive" : "card"}>
Working example: https://codesandbox.io/s/mjryv01528
I can suggest two approaches to fix your problem.
Approach 1:
In your selectCard method, in addition to cardActive, store the Id of card into state.
In your render method, in map function, consider Id(saved in state ) also to either apply your cardActive class.
Approach2:
...
constructor(){
super();
this.state = {
cardActive: "",
customers: [...]
}
this.selectCard = this.selectCard.bind(this);
this.getCardClass = this.getCardClass.bind(this);
}
selectCard(offerId){
this.setState({ cardActive: offerId })
}
getCardClass(offerId) {
const { cardActive } = this.state;
return offerId === cardActive ? 'cardActive' : 'card';
}
render() {
...
customer.Offers.map((Offer,index) => {
return <div key={index + Offer.OfferId} onClick={() => this.selectCard(Offer.OfferId)}>
<div item xs={12}>
<div className="card" class={this.getCardClass(Offer.OfferId)}>
<div className="container">
<h5><b>{Offer.OfferId}</b></h5>
<h2>{Offer.Name}</h2>
{Offer.Products.map((Product, index) => {
return <div key={index + Product.ProductId}>
<p>+ {Product.ProductName}</p>
</div>
})}
<h3>{Offer.Price}</h3>
</div>
</div>
</div>
</div>
})
...
}
Here the selected card is stored in the state instead of just the it being true
or false
. The selectCard
helper method sets the value of cardActive
while getCardClass
determines the selected card's class.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.