I have a React component which looks like this:
class Answers extends React.Component {
constructor(props) {
super(props);
}
handleCheck(e) {
alert(e.target);
}
render() {
return (
<div id="answers">
<ul>
<li onClick={this.handleCheck}><span>A</span> <p>{this.props.answers[0]}</p></li>
<li onClick={this.handleCheck}><span>B</span> <p>{this.props.answers[1]}</p></li>
<li onClick={this.handleCheck}><span>C</span> <p>{this.props.answers[2]}</p></li>
<li onClick={this.handleCheck}><span>D</span> <p>{this.props.answers[3]}</p></li>
</ul>
</div>
);
}
}
As you can see, I have an onClick event on each li items.
All I want is to get the corresponding li when the user click that li.
The problem is that e.target, will get sometimes the <span>
and sometimes the <p>
tags… (which are the li’s children tags)
I don’t understand why is this happening. Can someone enlighten me? 
Thank you!
You can find and download the repo on github.
I’ve solved it by adding for each li’s a data-id attribute and binding the handleCheck method to this
.
<li onClick={this.handleCheck.bind(this)} data-id="1"><span>A</span> <p>{this.props.answers[0]}</p></li>
<li onClick={this.handleCheck.bind(this)} data-id="2"><span>B</span> <p>{this.props.answers[1]}</p></li>
<li onClick={this.handleCheck.bind(this)} data-id="3"><span>C</span> <p>{this.props.answers[2]}</p></li>
<li onClick={this.handleCheck.bind(this)} data-id="4"><span>D</span> <p>{this.props.answers[3]}</p></li>
And then in handleCheck
I’ll get the element with:
handleCheck(e) {
e.currentTarget.dataset.id
}
Can you put ‘this.handleCheck = this.handleCheck.bind(this)’ in your constructor to trim things down a bit?
1 Like
You are right.
thank you!
I was having a similar issue, I was able to solve it by using e.currentTarget.dataset.id instead of e.target.dataset.id. If I used e.target the onClick of the parent would still fire, but the data-id value would be undefined, which makes sense because the children elements do not have data-id set. But by using e.currentTarget instead, even clicking on a child element would still capture the correct data-id value.
This code is not actually tested because I’m short on time but it is linted.
Styles removed for readability except to show the parent / child boundaries.
Clicking on either the parent or the child should carry the data-id value into the setRejectionID onClick method.
Note that the setRejectionID method only needs to be bound once.
import React from 'react';
import { connect } from 'react-redux';
class Rejection extends React.Component {
constructor(props) {
super(props);
this.state = {
rejectionID: null,
rejections: [{
id: 0,
name: "First Rejection"
},
{
id: 1,
name: "Second Rejection"
}]
};
this.setRejectionID = this.setRejectionID.bind(this);
}
setRejectionID(e) {
let rejectionID = this.state.rejectionID;
if (e.currentTarget.dataset.id == 0 || e.currentTarget.dataset.id) {
rejectionID = e.currentTarget.dataset.id;
}
this.setState({ rejectionID });
}
render() {
let rejections = this.state.rejections;
let rejectionID = this.state.rejectionID;
let content;
// Display rejection if a rejection ID has been selected
if (!isNaN(rejectionID) || rejectionID == 0) { // If value is == 0 or is a number
// Get our rejection object
let rejection = rejections[rejectionID];
// Display the page to show the selected data
content = (<div><p>You have selected Rejection {rejection.name} which has ID {rejection.id}</p></div>);
} else { // If rejectionID is not set
if (rejections.length) {
let rejections = rejections
.map((rejection, i) => {
return (<li style={{ border: "1px solid #000000", width: "600px" }} key={i} data-id={rejection.id} onClick={this.setRejectionID}>
<span style={{ border: "1px solid #ff0000", width: "300px", margin: "20px" }}>Rejection for {rejection.name}</span>
</li>);
});
content = (<div>
<div>Please choose one:</div>
<div>
<ul>
{rejections}
</ul>
</div>
</div>);
} else {
content = (<div>There are no Rejections to choose from.</div>);
}
}
return (<div>
{content}
</div>);
}
}
export default Rejection;
You can try this
<ul> <li onClick={() => console.log("clicked!")}>A</li> </ul>