Search code examples
reactjsbootstrap-modalreact-bootstrap4-modal

How can i open just one modal through a map function


im trying to make a subpage for a record label, i need to display all the artists on cards and then have their full profile displayed on a modal, whenever i try to open the modal all of them open and close when i click the card button, i've tried creating a constructor(props) with state component but wasnt able to make the state recieve the key id of the artist . i've been trying for weeks trying to adapt other examples to my own code with no results, Thank you so much for your time!

import React, {useState, setShow, Component} from 'react';
import {CardDeck, Navbar, NavLink, Col, Row, Image, Container, Card, CardImg, CardBody, CardText } from 'react-bootstrap';
import Button from 'react-bootstrap/Button'; 
import Modal from 'react-bootstrap/Modal';

const Artistas = [ {id:1,
img:require("../assets/images/artists-01.jpg"), 
title: 'Artist 1', 
content: 'Lorem Ipsum',
    musica:"https://open.spotify.com/embed/artist/1wA3nwZy9EriceVVQlEmEx",
    genres:["Punk ", "Rock"]},
  
    {id: 2, 
img:require("../assets/images/artists-04.jpg"), 
title: "Artist 2", 
content: 'lorem ipsum',
    musica:"https://open.spotify.com/embed/artist/1wA3nwZy9EriceVVQlEmEx"},
   ];


function ArtistsPage() {
  
    
const [show, setShow] = useState(false);
  const handleClose = () => setShow(false);
  const handleShow = () => setShow(true);

const Artistxs = Artistas.map(artist => 
<div>
<Card key={artist.id}>
  <Card.Img variant="top" src={artist.img} />
  <Card.Body>
  <Button onClick={handleShow}>{artist.title}</Button>
 <Card.Text>
  </Card.Text> 
  </Card.Body>
</Card>
<>
<Modal
        show={show}
        onHide={handleClose}
        backdrop="static"
        keyboard={false}
        centered
        size="lg"
      >
        <Modal.Header closeButton>
          <Modal.Title>{artist.title}</Modal.Title>
        </Modal.Header>
        <Modal.Body className="row">
        <div class="col-md-8">
        <Image src={artist.img} />
  </div>
  <div class="col-md-4">
    <p>{artist.content}</p>
  </div>
        </Modal.Body>
        <Modal.Footer>
          <Button onClick={handleClose} >
            Close
          </Button>
        </Modal.Footer>
      </Modal>
</>
</div>
 )


  return(
    <div>
      <Container className="container">
<Row className="row">
  <Col className="">{Artistxs}
</Col>
</Row>
</Container>
</div>
  );

}



export default ArtistsPage; 

Solution

  • You can create separate component for Modal and pass the object through Props to display relevant info and handle modal events.

    In example below, not toggling the actual modal but u can use the props to toggle it.

    function ArtistAddtionalInfo(props) {
      return (
      // Modal can be here with details in artistInfo and other props 
      <div className="modal_dummy"> 
        Below Props can be used to handle actual model popup 
        <h1> Hello, { props.artistInfo.title }</h1>
        <div>{ props.artistInfo.id }</div>
        <div>{ props.artistInfo.img }</div>
        <div>{ props.artistInfo.content }</div>
        <div>showModel: {props.showModel ? 'true' : 'false'}</div>
        <button onClick = {() => props.handleModalClose()} > close </button>
      </div>
      
      )
    }
    
    class TodoApp extends React.Component {
      constructor(props) {
        super(props)
        this.state = {
            items: [ {id:1,
    img:"../assets/images/artists-01.jpg", 
    title: 'Artist 1', 
    content: 'Lorem Ipsum',
        musica:"https://open.spotify.com/embed/artist/1wA3nwZy9EriceVVQlEmEx",
        genres:["Punk ", "Rock"]},
      
        {id: 2, 
    img:"../assets/images/artists-04.jpg", 
    title: "Artist 2", 
    content: 'lorem ipsum',
        musica:"https://open.spotify.com/embed/artist/1wA3nwZy9EriceVVQlEmEx"},
       ],
       artistInfo:  {},
       isShowModel: false
        }
      }
      
    handleShow = (artist) =>{
         this.setState({
             artistInfo:artist,
           isShowModel: true
         });
      }
      
    handleOnhide = () =>{
         this.setState({
             isShowModel: false
         });
    }
    
    render() {
        return (
          <div className="container">
            <div className="row">
                <div className="">
                    { 
                    this.state.items.map(artist => 
                       <div className="card" key={artist.id}>
                        <img className="card_image" src={artist.img} />
                        <div className="card_body">
                            <button onClick={ () => { this.handleShow(artist)}}> {artist.title} </button>
                            <div className="card_text">
                            </div> 
                        </div>
                      </div>
                 )
                } 
              </div>
            </div>
            {
            this.state.isShowModel &&
            <ArtistAddtionalInfo 
              artistInfo = { this.state.artistInfo }
              showModel = {this.state.isShowModel}
              handleModalClose = {() => {this.handleOnhide()}}
            />
            }
          </div>
        )
      }
    }
    
    ReactDOM.render(<TodoApp />, document.querySelector("#app"))
    

    JSFiddle see it in action