Basit
Basit

Reputation: 367

Dynamic content with React js Modal

I want to get dynamic content with React js modal I am using package react-responsive-modal. First I render all the post through map. Now I want when I click the individual post the modal should pop up and show me only that particular post's title and body. Now I can't figure out how to get an individual post in modal. Is it possible to do that via third-party package or I have to make custom modal for that?

import React from 'react';
    import Modal from 'react-responsive-modal';
    import Axios from 'axios';

    const styles = {
        fontFamily: 'sans-serif',
        textAlign: 'center'
    };

    class App extends React.Component {
        state = {
            posts: [],
            open: false
        };

        componentDidMount() {
            let url = 'https://jsonplaceholder.typicode.com/posts';
            Axios.get(url).then(res => {
                this.setState({
                    posts: res.data.slice(0, 10)
                });
                console.log(res.data.slice(0, 10));
            });
        }

        onOpenModal = () => {
            this.setState({ open: true });
        };

        onCloseModal = () => {
            this.setState({ open: false });
        };

        renderPosts() {
            return this.state.posts.map(post => {
                return (
                    <div
                        key={post.id}
                        style={{ width: 400, height: 400, backgroundColor: 'orange' }}
                        onClick={this.onOpenModal}
                    >
                        <h1>{post.title}</h1>
                    </div>
                );
            });
        }

        renderModal(id, title, body) {
            return this.state.posts.map(post => {
                return (
                    <div key={post.id} style={{ width: 400, height: 400, backgroundColor: 'orange' }}>
                        <h1>{post.id}</h1>
                        <h1>{post.title}</h1>
                        <p>{post.body}</p>
                    </div>
                );
            });
        }

        render() {
            const { open } = this.state;
            return (
                <div style={styles}>
                    <h2>react-responsive-modal</h2>

                    <div>{this.renderPosts()}</div>
                    <Modal open={open} onClose={this.onCloseModal} center>
                        <h2>Simple centered modal</h2>
                        <div>{this.renderModal()}</div>
                    </Modal>
                </div>
            );
        }
    }

    export default App;

Upvotes: 2

Views: 21050

Answers (4)

Farhan Ali Raza
Farhan Ali Raza

Reputation: 19

Using React Hooks

Create a modal with dynamic props like this

export default function Modal({
  open,
  setOpen,
  onConfirm,
  title,
  description,
  confirmText,
}) 

Then render the component. i did it like this

const getModal = () => {
    return (
        <Modal open={open} setOpen={setOpen} title={title} description={description} confirmText={confirmText} onConfirm={confirmAction} />
    )
}

and then when you want to display your dynamic modal use a function like this ConfirmAction can not be a function you should call the function inside that Modal according to that confirmation

const createModal = (title, description, confirmText, confirmAction) => {
    setTitle(title);
    setDescription(description);
    setConfirmText(confirmText);
    setConfirmAction(confirmAction);
    setOpen(true);
}

Upvotes: 0

ethan.roday
ethan.roday

Reputation: 2635

You'll need to introduce some additional state on your App component that keeps track of the currently selected post. In your onOpenModal() method, you can update that state with the index of the post that was clicked. Then, in renderModal(), you can check what the selected post is and only render that post instead of mapping over the entire array.

class App extends React.Component {
  state = {
    posts: [],
    open: false,
    selectedPost: null // Keep track of the selected post
  };

  componentDidMount() {
    let url = "https://jsonplaceholder.typicode.com/posts";
    Axios.get(url).then(res => {
      this.setState({
        posts: res.data.slice(0, 10)
      });
      console.log(res.data.slice(0, 10));
    });
  }

  onOpenModal = i => {
    this.setState({
      open: true,
      selectedPost: i // When a post is clicked, mark it as selected
    });
  };

  onCloseModal = () => {
    this.setState({ open: false });
  };

  renderPosts = () => {
    return this.state.posts.map((post, i) => {
      return (
        <div
          key={post.id}
          style={{ width: 400, height: 400, backgroundColor: "orange" }}
          onClick={() => this.onOpenModal(i)} // Pass the id of the clicked post
        >
          <h1>{post.title}</h1>
        </div>
      );
    });
  }

  renderModal = () => {
    // Check to see if there's a selected post. If so, render it.
    if (this.state.selectedPost !== null) {
      const post = this.state.posts[this.state.selectedPost];
      return (
        <div
          style={{ width: 400, height: 400, backgroundColor: "orange" }}
        >
          <h1>{post.id}</h1>
          <h1>{post.title}</h1>
          <p>{post.body}</p>
        </div>
      );
    }
  }

  render() {
    const { open } = this.state;
    return (
      <div style={styles}>
        <h2>react-responsive-modal</h2>

        <div>{this.renderPosts()}</div>
        <Modal open={open} onClose={this.onCloseModal} center>
          <h2>Simple centered modal</h2>
          <div>{this.renderModal()}</div>
        </Modal>
      </div>
    );
  }
}

Upvotes: 11

varoons
varoons

Reputation: 3887

In the post onClick function set the post id/index in state along with the open flag

Inside the modal render use the saved index/id to pass that post to the modal as a param/prop.

You dont need to map over all posts inside the modal.

Sample

onOpenModal = (index) => {
   this.setState({ open: true, selectedPostIndex: index });
};

onCloseModal = () => {
   this.setState({ open: false, selectedPostIndex: undefined })
}

renderPosts() {
   return this.state.posts.map((post, index) => {
      return (
         <div key={post.id} onClick={() => this.onOpenModal(index)}>
            <h1>{post.title}</h1>
         </div>
      )
   })
}

render() {
....
  <Modal open={open} onClose={this.onCloseModal} center>
    <h2>Simple centered modal</h2>
    <div>{this.renderModal(this.state.posts[this.state.selectedPostIndex])}</div>
  </Modal>
 ....
}

renderModal(post) {
   return (
      <div key={post.id} style={{ width: 400, height: 400, backgroundColor: 'orange' }}>
         <h1>{post.id}</h1>
         <h1>{post.title}</h1>
         <p>{post.body}</p>
      </div>
   )
}

Upvotes: 1

Anil Kumar
Anil Kumar

Reputation: 2309

Initialize your state with one array which will hold

state = {
        posts: [],
        open: false,
        modalShow: [false,false,false,false,false,false,false,false,false,false] // this is 10 as you have only 10 posts
    };

Now modify render posts

    onOpenModal = (id) => {
        const newModalShow = [...this.state.modalShow];
        newModalShow[id] = true; 
        this.setState({ modalShow: newModalShow});
    };


    renderPosts() {
        return this.state.posts.map((post,index) => {
            return (
                <Fragement>
                <div
                    key={post.id}
                    style={{ width: 400, height: 400, backgroundColor: 'orange' }}
                    onClick={()=>this.onOpenModal(index)}
                >
                    <h1>{post.title}</h1>
                </div>
                <Modal open={this.state.modalShow[index]} onClose={this.onCloseModal} center>
                    <h2>post.title</h2>
                    <div>{this.renderModal()}</div>
                </Modal>
               <Fragement>
            );
        });
    }

Upvotes: -1

Related Questions