Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Render Multiple Modals correctly with map in react-bootstrap

I am trying to render multiple react-bootsrap modals with map but I am unable to do so. With my current code clicking the 'View Details' button is activating all the modals at the same time instead of opening the relevant modal. Here's a snippet from my code related to the modal:

  render() {
    const { accounts } = this.props;
    const displayAccounts = Object.keys(accounts).filter(key => {
      return accounts[key].info.type === 'student'
    }).map(key => {
      return (
        <tr key={key}>
          <th>{accounts[key].info.name}</th>
          <td>{accounts[key].info.email}</td>
          <td><Button bsStyle='danger' onClick={() => this.props.removeAccount(key)}>Remove Account</Button></td>
          <td>
            <ButtonToolbar>
              <Button id={key} bsStyle="primary" onClick={this.showModal}>View Details</Button>
              <Modal
                id={key}
                show={this.state.show}
                onHide={this.hideModal}
              >
                <Modal.Header closeButton>
                  <Modal.Title>Student Details</Modal.Title>
                </Modal.Header>
                <Modal.Body>
                  <Table responsive striped hover>
                    <thead>
                      <tr>
                        <th>Title</th>
                        <th>Details</th>
                      </tr>
                    </thead>
                    <tbody>
                      <tr>
                        <th>Name</th>
                        <td>{accounts[key].userDetails.name}</td>
                      </tr>
                      <tr>
                        <th>Education</th>
                        <td>{accounts[key].userDetails.education}</td>
                      </tr>
                      <tr>
                        <th>GPA</th>
                        <td>{accounts[key].userDetails.gpa}</td>
                      </tr>
                      <tr>
                        <th>Skills</th>
                        <td>{accounts[key].userDetails.skills}</td>
                      </tr>
                      <tr>
                        <th>Overview</th>
                        <td>{accounts[key].userDetails.skills}</td>
                      </tr>
                    </tbody>
                  </Table>
                </Modal.Body>
                <Modal.Footer>
                  <Button onClick={this.hideModal}>Close</Button>
                </Modal.Footer>
              </Modal>
            </ButtonToolbar>
          </td>
        </tr>
      )
    })
like image 510
Ghulam Muhammad Avatar asked Aug 06 '17 21:08

Ghulam Muhammad


1 Answers

Try making the following modifications...

Add the following change to this.state in your constructor to cache the active Modal index to be assigned later.

this.state = {
    ...,
    activeModal: null,
    ...,
}
this.clickHandler = this.clickHandler.bind(this);
this.hideModal = this.hideModal.bind(this);

Add/Change the following Event Handlers. The clickHandler accepts the click event as well as an index that will be used to set the aforementioned activeModal piece of state. When react sees that the state changed it will call the render method with the new state. This is the Reactive nature of React.

clickHandler(e, index) {
    this.setState({ activeModal: index })
}

hideModal() {
    this.setState({ activeModal: null })
}

Do something like this in your map function. Notice the onClick handler. Use an arrow function to catch the click event and call your clickHandler, this is so you can also pass additional arguments (this index in this case). Once the activeModal piece of state is called the component will be rerendered, upon doing to the show prop will evaluate to true for the appropriate clicked component.

buttonArray.map((button, index) => {
    <Button id={key} bsStyle="primary" onClick={e => this.clickHandler(e, index)}>View Details</Button>
    <Modal
        id={key}
        show={this.state.activeModal === index}
        onHide={this.hideModal}
    />
} )
like image 155
canaan seaton Avatar answered Oct 25 '22 18:10

canaan seaton