0
votes

I'm trying to open a modal dialog from a set of cards that has been looping from the data the component receives. I can't figure it out how to make the modal get the appropriate data from the clicked card. In my code below, I tried to put the modal outside the loop, but then I can't figure it out how to pass the id of the clicked card to a new function which would control the modal

Here is the Component that manages the cards loop and contains the modal

import React, {Component} from 'react';
import {Nav, NavItem, NavLink, Card, CardImg, CardText,
  CardBody, CardTitle, CardSubtitle, FormGroup, Input, Col, Button, Modal, ModalHeader, ModalBody} from 'reactstrap';
import classnames from 'classnames';


class ProductCard extends Component {
  constructor(props){
    super(props);
    this.state={
      productList: this.props.products,
      isModalOpen: false
    }
    this.toggleModal = this.toggleModal.bind(this)
  }

  toggleModal() {
    this.setState({
      isModalOpen: !this.state.isModalOpen
    });
  }

  render(){
    return(
      this.state.productList.map(prod => (
        <div key={prod.prod_id} className="col-12 col-md-3 mb-4 rowCard" onClick={this.toggleModal}>
            <Card>
              <CardImg top width="100%" src={prod.prod_image}  alt={prod.prod_name_eng}/>
              <CardBody>
                <CardTitle>{prod.prod_name_eng}</CardTitle>
                <CardSubtitle>{prod.prod_cost_total}</CardSubtitle>
                <CardText>{prod.prod_description}</CardText>
              </CardBody>
            </Card>
            <Modal isOpen={this.state.isModalOpen} toggle={this.toggleModal}>
              <ModalHeader toggle={this.toggleModal}>{prod.prod_name_eng}</ModalHeader>
              <ModalBody>{prod.prod_description}</ModalBody>
            </Modal>
        </div>
      )) 
    );
  }
}

Any help is welcome! thanks

1

1 Answers

0
votes

I would suggest moving the Modal outside of your map, since that makes things more complicated than they need to be. If you do this, then you toggleModal method is then responsible for accepting an index (supplied by the map function) and then you would just need to retrieve the correct text for the modal elements.

  toggleModal(index) {
    this.setState({
      cardIndex: index,
      isModalOpen: !this.state.isModalOpen
    });
  }

Then you're modal just needs to reference the productList in state, access the index and get the title and description:

class ProductCard extends Component {
  constructor(props) {
    super(props);
    this.state = {
      productList: this.props.products,
      cardIndex: null,
      isModalOpen: false
    };
    this.toggleModal = this.toggleModal.bind(this);
  }

  toggleModal(id) {
    console.log(id);
    this.setState({
      cardIndex: id,
      isModalOpen: !this.state.isModalOpen
    });
  }

  render() {
    const { productList, cardIndex } = this.state;
    console.log("CardIndex: ", cardIndex);
    console.log("Product: ", productList[cardIndex]);
    return (
      <Fragment>
        {productList.map((prod, index) => {
          return (
            <div
              key={prod.prod_id}
              className="col-12 col-md-3 mb-4 rowCard"
              onClick={e => this.toggleModal(index)}
            >
              <Card>
                <CardImg top src={prod.prod_image} alt={prod.prod_name_eng} />
                <CardBody>
                  <CardTitle>{prod.prod_name_eng}</CardTitle>
                  <CardSubtitle>{prod.prod_cost_total}</CardSubtitle>
                  <CardText>{prod.prod_description}</CardText>
                </CardBody>
              </Card>
            </div>
          );
        })}
        <Modal
          isOpen={this.state.isModalOpen}
          toggle={e => this.toggleModal(cardIndex)}
        >
          <ModalHeader toggle={e => this.toggleModal(cardIndex)}>
            {cardIndex !== null && productList[cardIndex].prod_name_eng}
          </ModalHeader>
          <ModalBody>
            {cardIndex !== null && productList[cardIndex].prod_description}
          </ModalBody>
        </Modal>
      </Fragment>
    );
  }
}

Here is a codesandbox link to a working version: