1

I'm trying to add interactivity to a four quadrant chart whereby the user can click a box to highlight it, and the others will deactivate, similar to how radio boxes work in a form.

The idea was to add an onClick event to each card and have a handler function that will check which box was clicked on, activate it, and then deactivate the rest.

The problem I'm having is that e.target seems to be picking up the child nodes of each card instead of the card itself, so I'm having trouble figuring out which card was clicked.

e.g. console log = '>> event.target <li>A</li>' 

I was hoping to determine which card was picked by doing something like event.target.id

I've tried a bunch of things and nothing has worked... How do people normally set this type of interaction up?

import React from "react"; import Card from "@material-ui/core/Card"; import CardContent from "@material-ui/core/CardContent"; import CardActionArea from '@material-ui/core/CardActionArea'; import Typography from "@material-ui/core/Typography"; import Paper from "@material-ui/core/Paper"; function MyCard({ title }) { return ( <CardActionArea onClick={quadrantClickHandler}> <Card> <CardContent> <Typography>{title}</Typography> </CardContent> </Card> </CardActionArea> ); } function quadrantClickHandler(e) { e.stopPropagation(); console.log('>> event.target ',e.target); //the idea here is that I will click a "card" //and then determine which card was clicked so that //I can highlight it similar to a radio box set in a form. } function Quadrants() { return ( <React.Fragment> <MyCard title={ <ul> <li>A</li> <li>B</li> <li>C</li> <li>D</li> <li>E</li> <li>F</li> <li>G</li> </ul> } /> <MyCard title="Fast but expensive" /> <MyCard title="Slow but Cheap" /> <MyCard title="Slow but Fast" /> </React.Fragment> ); } function FourQuadrants() { const classes = useStyles(); return ( <div> <h2>Make a choice:</h2> <Paper className={classes.paper}> <Typography className={classes.top}>Big</Typography> <Typography className={classes.bottom}>Small</Typography> <Typography align="center" className={classes.left}>Expensive</Typography> <Typography align="center" className={classes.right}>Cheap</Typography> <Quadrants /> </Paper> </div> ); } export default FourQuadrants; 

1 Answer 1

2

Rather than trying to pull information out of the event target, you can have the click handler know everything of importance.

The key aspects in my example below are:

  • State at the top level (selectedId) to track which card is selected
  • A click-handler that knows the id of its card and sets the selectedId accordingly
  • I'm providing each card with its own id and the selectedId, so that it can style itself differently based on whether or not it is selected
import ReactDOM from "react-dom"; import React from "react"; import Card from "@material-ui/core/Card"; import CardContent from "@material-ui/core/CardContent"; import CardActionArea from "@material-ui/core/CardActionArea"; import Typography from "@material-ui/core/Typography"; import { makeStyles } from "@material-ui/core"; const useStyles = makeStyles({ selected: { border: "1px solid green" } }); function MyCard({ title, id, selectedId, handleClick }) { const classes = useStyles(); return ( <Card className={id === selectedId ? classes.selected : null}> <CardActionArea onClick={handleClick(id)}> <CardContent> <Typography>{title}</Typography> </CardContent> </CardActionArea> </Card> ); } function Quadrants() { const [selectedId, setSelectedId] = React.useState(); const handleClick = id => e => { setSelectedId(id); }; const cardProps = { selectedId, handleClick }; return ( <React.Fragment> <MyCard {...cardProps} id={1} title={ <ul> <li>A</li> <li>B</li> <li>C</li> <li>D</li> <li>E</li> <li>F</li> <li>G</li> </ul> } /> <MyCard {...cardProps} id={2} title="Fast but expensive" /> <MyCard {...cardProps} id={3} title="Slow but Cheap" /> <MyCard {...cardProps} id={4} title="Slow but Fast" /> </React.Fragment> ); } function FourQuadrants() { return ( <div> <h2>Make a choice:</h2> <Quadrants /> </div> ); } function App() { return <FourQuadrants />; } const rootElement = document.getElementById("root"); ReactDOM.render(<App />, rootElement); 

Edit selected card

Sign up to request clarification or add additional context in comments.

2 Comments

Doesn't this <CardActionArea onClick={handleClick(id)}> call on mount?
@user981320 handleClick is called during render, but handleClick just returns a function (e => { setSelectedId(id); };) -- a function that knows the id that was passed to handleClick during render. That returned function will be called during click events.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.