Cmaxster
Cmaxster

Reputation: 1195

onClick Handler in React Picking Up Child Nodes

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;

Upvotes: 1

Views: 352

Answers (1)

Ryan Cogswell
Ryan Cogswell

Reputation: 81066

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

Upvotes: 2

Related Questions