I'm trying to add the onClick event on the data I selected from the AsyncTypeahead. I'm passing the callback function to the Problem that renders only if I've selected an item. But after selecting an item it directly calling the callback function that I passed to Problem component
This is main Component
constructor(props) {
super(props);
this.state = {
plateform: '',
selected: [],
isLoading: false,
options: []
};
this.handleInputChange = this.handleInputChange.bind(this);
this.saveTodo = this.saveTodo.bind(this);
}
async handleInputChange(event) {
const target = event.target;
const value = target.value;
const name = target.name;
await this.setState({
[name]: value
});
}
saveTodo(problemID) {
axios.post(`${API}/todos`,
{
problemID: problemID
},
{
headers: {
Accept: "application/json",
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + this.props.auth.token
}
})
.then(() => alert("Problem saved to todo list"))
.catch((err) => {
if (err.response) {
alert(err.response.data);
}
else {
alert("Sorry! A server error occurred. Try to save this problem later!");
}
});
}
render() {
return (
<>
<TrainLayout auth={this.props.auth} deauthenticate={this.props.deauthenticate} title={title} description={description} >
<div className="container">
<div className="row justify-content-center">
<div className="offset-md-3 col-md-7 offset-2">
<br />
<div className="form-group row">
<label htmlFor="oj" className="col-4 col-form-label col-form-label-sm">Online Judge</label>
<div className="col-8 col-md-5">
<select id="oj" type="select" className="form-control form-control-sm" name="plateform" onChange={this.handleInputChange} value={this.state.plateform}>
<option value="all">All Online Judges</option>
<option value="xxx">XXX</option>
<option value="yyy">YYY</option>
<option value="zzz">ZZZ</option>
</select>
</div>
</div>
<div className="form-group row">
<label htmlFor="pname" className="col-4 col-form-label col-form-label-sm">Problem Name</label>
<div className="col-8 col-md-5">
<AsyncTypeahead
isLoading={this.state.isLoading}
allowNew={false}
multiple={false}
id="pname"
labelKey={option => `${option.name} (${option.plateform})`}
minLength={2}
onChange={selected => this.setState({ selected })}
placeholder="Search for a problem"
onSearch={query => {
this.setState({isLoading: true});
axios.get(`${API}/problems/${query}`,
{
params: {
plateform: this.state.plateform
},
headers: {
Accept: "application/json",
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + this.props.auth.token
}
})
.then((response) => { /* eslint-disable-line camelcase */
const options = response.data.map((problem) => ({
_id: problem._id,
problemID: problem.problemID,
name: problem.name,
plateform: problem.plateform,
link: problem.link,
difficulty: problem.difficulty
}));
console.log("DATA: ", options);
this.setState({
isLoading: false,
options: options,
});
});
}}
options={this.state.options} />
</div>
</div>
</div>
</div>
</div>
<br /><br />
<div className="container">
<div className="row justify-content-center">
{!!this.state.selected &&
(
<Problem saveTodo={this.saveTodo} problem={this.state.selected[0]} />)
}
</div>
</div>
</TrainLayout>
</>
);
}
I expect the Onclick event to be called when I click on the font-awesome icon but it fires when I select an item from AsyncTypeahead
const Problem = ({problem, saveTodo}) => {
if (!problem) {
return (
<></>
);
}
return (
<>
<table className="table table-sm table-bordered table-striped table-responsive-sm table-hover">
<thead>
<tr className="text-center">
<th>Name</th>
<th>Online Judge</th>
<th>Difficulty</th>
<th>Add Todo</th>
<th>Solve</th>
</tr>
</thead>
<tbody>
<tr className="text-center">
<td> {problem.name} </td>
<td> {problem.plateform} </td>
<td> {problem.difficulty} </td>
<td> <a onClick={saveTodo(problem.problemID)}><FontAwesomeIcon icon="save" /></a> </td>
<td> <a href={`${problem.link}`} target="_blank"> Solve </a> </td>
</tr>
</tbody>
</table>
<br />
<div className="row justify-content-center">
<p>Note: Difficulty is not 100% accurate</p>
</div>
</>
);}
You should be passing a function as the event handler. In your example you are calling the function immediately. Try the following.
<td> <a onClick={() => saveTodo(problem.problemID)}><FontAwesomeIcon icon="save" /></a> </td>
See Handling Events - React for more info.