Toggle modal in React to display card-specific information

In my project, I have a series of cards with specific data such as job numbers and titles. To provide more details about each job, I implemented a pop-up modal that can be accessed by clicking the "View Details" button on each card. The idea is to display additional information related to the specific card when the button is clicked.

However, one issue I encountered is that all the modals are rendered at once because there's only one toggleModal function assigned to each button. What I'm aiming for is to show details from the card you selected instead of displaying all pop-ups simultaneously.

I've been experimenting with different solutions as I'm relatively new to working with React.

The challenge lies in determining which card triggered the click event so that only that particular modal is displayed. Here is the code snippet:

function ActiveJobs() {
  const [cards] = React.useState([
    {
      title: "Customer Name: Smith, James",
      jobnum: "Job Number: 1829",
      crewnum: "Crew: 0/2",
      address: "1825 Olive Ave",
    },
    ...
];

const [modal, setModal] = React.useState(false);

const toggleModal = () => {
  setModal(!modal);
};

if (modal) {
  document.body.classList.add("active-modal");
} else {
  document.body.classList.remove("active-modal");
}

return (
  <div>
    <section>
      <div className="container">
        <h1>All Active Jobs</h1>
        <div className="cards">
          {cards.map((card, i) => (
            <div key={i} className="card">
              <h3>{card.title}</h3>
              <p>{card.jobnum}</p>
              <p>{card.crewnum}</p>
              <p>{card.address}</p>
              <button className="cardbtn" onClick={toggleModal}>
                View Details
              </button>
              <button className="cardbtn">Assign Crew</button>
              {modal && (
                <div className="modal">
                  <div onClick={toggleModal} className="overlay"></div>
                  <div className="modal-content">
                    <h2>Job Details</h2>
                    <p>{card.title}</p>
                    <p>{card.jobnum}</p>
                    <p>{card.crewnum}</p>
                    <p>{card.address}</p>
                    <button className="close-modal" onClick={toggleModal}>
                      CLOSE
                    </button>
                  </div>
                </div>
              )}
            </div>
          ))}
        </div>
      </div>
    </section>
  </div>
);
}
...
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>

Answer №1

You can use a unique identifier or index in the modal variable to determine which modal needs to be shown.

const [modalInfo, setModalInfo] = useState({
  id: null,
  isVisible: false,
});

To handle the display of modals when the "View Details" button is clicked, you should create a separate function. This ensures that clicking the button will either show or hide the modal based on its current state.

const toggleModal = () => {
  setModalInfo((prevModalInfo) => ({
    ...prevModalInfo,
    isVisible: !prevModalInfo.isVisible,
  }));
};

const displayModalDetails = (id) => {
  setModalInfo((prevModalInfo) => ({
      id,
      isVisible: true,
    }));
};

<button className="cardbtn" onClick={() => displayModalDetails(i}>
  View Details
 </button>

For updating body classes based on modal visibility, it's recommended to utilize the useEffect hook. Since updating the document directly is outside React's scope, useEffect helps manage such side effects. If you need help understanding how useEffect works, check out these resources: Absolute Beginners Guide to useEffect, w3schools - React useEffect, React useEffect Reference

useEffect(() => {
  if (modalInfo.isVisible) {
    document.body.classList.add("active-modal");
  } else {
    document.body.classList.remove("active-modal");
  }
}, [modalInfo.isVisible])

All the code components combined would look something like this:

import { useState } from "react";
    import "./ActiveJobs.css";

    export default function ActiveJobs() {
  const [cards] = useState([
    {
      title: "Customer Name: Smith, James",
      jobnum: "Job Number: 1829",
      crewnum: "Crew: 0/2",
      address: "1825 Olive Ave",
    },
    {
      title: "Customer Name: Cherry, John",
      jobnum: "Job Number: 8421",
      crewnum: "Crew: 0/3",
      address: "256 Milwood Sq",
    },
    {
      title: "Customer Name: Rudd, Paul",
      jobnum: "Job Number: 0281",
      crewnum: "Crew: 0/4",
      address: "4272 Lowes Island Blvd",
    },
    {
      title: "Customer Name: Robbie, Margot",
      jobnum: "Job Number: 2516",
      crewnum: "Crew: 0/3",
      address: "265 Atlas Lane",
    },
    {
      title: "Customer Name: Bond, James",
      jobnum: "Job Number: 0420",
      crewnum: "Crew: 0/5",
      address: "1418 10th Ave",
    },
    {
      title: "Customer Name: Jordan, Micheal",
      jobnum: "Job Number: 7617",
      crewnum: "Crew: 0/10",
      address: "180 Goat Dr",
    },
  ]);

  const [modalInfo, setModalInfo] = useState({
    id: null,
    isVisible: false,
  });

  const displayModalDetails = (id) => {
    setModalInfo((prevModalInfo) => ({
      id,
      isVisible: true,
    }));
  };

  const toggleModal = () => {
    setModalInfo((prevModalInfo) => ({
      ...prevModalInfo,
      isVisible: !prevModalInfo.isVisible,
    }));
  };

  useEffect(() => {
    if (modalInfo.isVisible) {
      document.body.classList.add("active-modal");
    } else {
      document.body.classList.remove("active-modal");
    }
  }, [modalInfo.isVisible])

  return (
    <div>
      <section>
        <div className="container">
          <h1>All Active Jobs</h1>
          <div className="cards">
            {cards.map((card, i) => (
              <div key={i} className="card">
                <h3>{card.title}</h3>
                <p>{card.jobnum}</p>
                <p>{card.crewnum}</p>
                <p>{card.address}</p>
                <button className="cardbtn" onClick={() => displayModalDetails(i)}>
                  View Details
                </button>
                <button className="cardbtn">Assign Crew</button>
                {modalInfo.isVisible && modalInfo.id === i && (
                  <div className="modal">
                    <div onClick={toggleModal} className="overlay"></div>
                    <div className="modal-content">
                      <h2>Job Details</h2>
                      <p>{card.title}</p>
                      <p>{card.jobnum}</p>
                      <p>{card.crewnum}</p>
                      <p>{card.address}</p>
                      <button className="close-modal" onClick={toggleModal}>
                        CLOSE
                      </button>
                    </div>
                  </div>
                )}
              </div>
            ))}
          </div>
        </div>
      </section>
    </div>
    );
   }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

"Utilize React to dynamically render Material UI icons in a web application

Hey there, I could use some help with a certain issue. In my project, I'm utilizing Material UI icons and they are set up in a way where I have to import them like this: import {Muicon } from '@/lib/material'; ... <Muicon.Visibility /& ...

TypeScript is unaware that a component receives a necessary prop from a Higher Order Component (HOC)

My component export is wrapped with a higher-order component (HOC) that adds a required prop to it, but TypeScript seems unaware that this prop has already been added by the HOC. Here's the Component: import * as React from "react"; import { withTex ...

What is causing the 'Invalid Hook Call' error to appear in React?

I have recently started learning React and I am currently working on converting a functional component into a class component. However, I encountered an error message that says: Error: Invalid hook call. Hooks can only be called inside of the body of a fu ...

React warning: Make sure every child element in a list has a distinct "key" property assigned

Here is a breakdown of my code that consists of 2 components and index.tsx: NewsFeed.tsx import React, { useState } from 'react' import Feeds from './Feeds' export default function NewsFeed({ news }: any) { const [date, setDate] ...

Issues with Stripe Checkout Integration in Nextjs and Django Environment

Currently, I am working on creating a payment page in Next.js using Stripe. Following the guide works perfectly fine, but I am exploring an alternative approach. Instead of using a form to call the /create-checkout-session endpoint, I want to trigger this ...

React JS: How to prevent Yup and Formik error messages from being displayed multiple times upon submission

I have implemented Yup and Formik in my Sign up form to handle validation. My goal is to display specific errors based on the Yup validation rules I've set up. Take a look at the code snippet below: import React from 'react'; import { ...

Implementing dynamic rendering of elements in Next.js using data from FaunaDB

I am currently working on a feature that displays different elements based on the users' job profile status. To fetch the necessary data, I'm utilizing FaunaDB along with useSWR. When I console.log(userData), I receive the following object: jobPr ...

What is the speed of retrieving new data once it has been inserted into a firebase real-time database?

In the midst of developing my personal project using next.js, I've encountered an issue with a component that includes a getstaticprops function. This function scrapes a website and then posts the extracted data to a firebase realtime database. Howeve ...

Interface not being assigned payload by Account Reducer

I'm currently facing an issue while trying to update an interface with a reducer payload obtained from one of my context providers. As a newcomer to GraphQL and React, I admit my lack of proficiency in explaining the problem but here goes. My situati ...

Find the perfect match with Material UI Autocomplete's feature that allows you to search from the start of

Implementing material UI Autocomplete field in my React project, I aim to restrict search functionality to only match keywords from the beginning (for certain fields of the objects): Here's an example scenario with the available options: [ {data1: ...

Getting a single value in a react-select dropdown can be achieved by accessing the selected

My goal is to implement a multi-select dropdown indicator, inspired by the second element in the example shown here, using react-select. This feature will display all blog post categories on a blog page and allow users to select specific categories to fil ...

Seamless integration of NextJS with Woocommerce backend

I am currently in the process of integrating NextJS with a backend WooCommerce using GraphQL. One thing that I have been pondering is how to reconfigure the setup. Currently, Wordpress/WooCommerce is set up as follows: mywebwoo.com - default WordPress sto ...

Incorporating Bootstrap Navbar into a create-react-app project

I recently created a new project using create-react-app. To incorporate Bootstrap into my project, I followed these steps: npm install --save bootstrap@3 Next, I imported Bootstrap in my root file index.js: import 'bootstrap/dist/css/bootstrap.css& ...

Prisma data is not being returned as an array in getServerProps with React Next.js

My Journey with Next.js and Prisma Having recently grasped the concept of getServerProps, I embarked on a project that involved retrieving data from a PostgreSQL database using Prisma. However, despite diligently following the syntax rules outlined in the ...

The react-redux developer tool appears to be disabled and is not displaying the current state of the application on the extension toolbar

Just finished the redux-tutorial and attempting to view the state in the redux-devtools. However, the redux-devtools seems to be inactive on the extensions bar. Upon clicking it, a menu appears with options like "to right, to left etc". Selecting one of ...

In React, the functionality of rendering components conditionally is not functioning properly

I am looking to conditionally display either the Login component or Menubar component based on the value of the isLogin state. If the isLogin state is false, I want to render the login page. If it is true, I want to render the Menubar page. To achieve thi ...

What is the Redux Toolkit equivalent of setting fetch's { credentials: "include" } in createApi?

In my project, I am utilizing an express-react-typescript-redux-passport setup where I'm making use of createApi from Redux Toolkit to make a call to a /getuser API on the backend. The authentication process involves the use of the passport-google-oa ...

How to Apply backgroundColor and onClick in a Basic React App: Overcoming Limitations

Currently, I am diving into a React tutorial that focuses on Hooks. The Hooks section is running smoothly for me. The author demonstrates how to personalize Hooks using simple styles and related components. Here's the snippet of code I have: import R ...

Show the 'No Records Found' message once a filter has been applied in the MUI DataGrid

NoRowsOverlay is failing to display when a filter is applied and no rows are left to show. Below is the code snippet: function customNoRowsOverlay() { return ( <GridOverlay> <div>No Rows</div> </GridOve ...

How can I make this div appear on the screen?

I have recently encountered an issue with a navbar on my webpage. Despite adding all the necessary links, one of them mysteriously disappears from view. It seems to be present when inspected in the console, but it just won't display on the front end. ...