Octavio Kh
Octavio Kh

Reputation: 35

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; 

Upvotes: 1

Views: 2605

Answers (2)

Guruling Kumbhar
Guruling Kumbhar

Reputation: 1049

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

Upvotes: 0

Davin Tryon
Davin Tryon

Reputation: 67296

You only need 1 Modal. So you can move Modal out of your map.

Then, you need to figure out how to indicate which artist to show in the Modal.

One way to do that is to pass the artist.id:

<Button onClick={handleShow(artist.id)}>{artist.title}</Button>

But now handleShow needs to return a function:

const handleShow = (artistId) => () => setShow(artistId);

I've also changes show to be which artist id instead of a boolean. (This assumes artist ids will not be zero, at the moment)

Once in the Modal, you need to find the selected artist:

Artistxs.find(artist => artist.id === artistId);

This should get you going.

Upvotes: 0

Related Questions