so I've got a table displaying multiple jobs from an API call. Each table row has a button that opens a bootstrap modal displaying further information about said job.
My problem is that the modal doesn't seem to be opening for the row clicked. It always opens a specific row (the one with the lowest id). Anyone know what I'm doing wrong?
ModalComponent
render() {
console.log("job: ", this.props.id)
return (
<div className="container">
<ReactBootstrap.Modal
{...this.props}
size="lg"
aria-labelledby="contained-modal-title-vcenter"
centered
>
<ReactBootstrap.Modal.Header closeButton>
<ReactBootstrap.Modal.Title id="contained-modal-title-vcenter">
{this.props.title}
{this.props.employer}
</ReactBootstrap.Modal.Title>
</ReactBootstrap.Modal.Header>
<ReactBootstrap.Modal.Body>
<h4>Would you like to apply to this job?</h4>
<p>{this.props.description}</p>
</ReactBootstrap.Modal.Body>
<ReactBootstrap.Modal.Footer>
<button className="btn btn-primary" onClick={this.applyJob}>Apply</button>
<button className="btn btn-warning" onClick={this.props.onHide}>Close</button>
</ReactBootstrap.Modal.Footer>
</ReactBootstrap.Modal>
</div>
)
}
The console.log
spits out the id of every row in the table.
My TableComponent
passes the job details of each job into the ModalComponent
like so:
TableComponent
<tbody>
{
this.props.response.map( // map allows you to loop around items
job => // a key is used to identify a row
<tr key={job.id}>
<td>{job.employer}</td>
<td>{job.jobTitle}</td>
<td>{job.county}</td>
{/* <td>{job.applied + ''}</td> */}
<td>
{this.checkApplied(job.applied)}
</td>
<td><button className="btn btn-info" onClick={() => this.setState({ addModalShow: true })}>Info</button></td>
<ApplyComponent
show={this.state.addModalShow}
onHide={addModalClose}
id={job.id}
title={job.jobTitle}
employer={job.employer}
county={job.county}
description={job.description}
status={job.applied}
/>
</tr>
)
}
</tbody>
Here are images of the table and the modal:
As you can see, the details form the bottom row is being displayed in the modal even when I click the top row.
You are mapping over several items that can each have their own modal. Each of those modals determines whether it is open or closed by the show
prop.
The show
prop is set to this.state.addModalShow
for every mapped element.
Every modal will open and close at the same time since they are based on the same state value. Clicking any item will cause all to open or close.
The visible result is that you will always see the last modal as the open modal, since it was the last to render and will be on top.
Here is one solution that would require minimal changes:
Use a different value in state for each item.
this.props.response.map(
job =>
<tr key={job.id}>
<td>{job.employer}</td>
<td>{job.jobTitle}</td>
<td>{job.county}</td>
<td>
{this.checkApplied(job.applied)}
</td>
<td>
<button
className="btn btn-info"
onClick={() => {
// Use a computed property name to make it unique based on the ID
this.setState({ ['show_'+job.id]: true })
}
>Info</button></td>
<ApplyComponent
show={this.state['show_'+job.id]} // Use the same state value as the prop
onHide={() => {
// Follow the same process for closing
this.setState({ ['show_'+job.id]: false})
}}
id={job.id}
title={job.jobTitle}
employer={job.employer}
county={job.county}
description={job.description}
status={job.applied}
/>
</tr>
)