Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Unable to trigger Modal from button within table row in React

I have two files: Modal.js and Users.js. Users.js contains a table that has an API get query mapped to it, in the final column of the table is a a dropdown for each row that contains three buttons; View, Edit and Delete. I would like the Delete button to trigger the Modal containing a message that roughly reads "Are you sure you wish to delete the user?".

I am struggling to get the Modal to trigger in the onClick event of the Delete component in the Users.js file, I’ll attach the code for the two files below.

Modal.js (I have not edited any of the content in the modal yet)

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

import {
  CButton,
  CModal,
  CModalHeader,
  CModalTitle,
  CModalBody,
  CModalFooter,
} from "@coreui/react";

const Modal = ({ visible, setVisible }) => {
  return (
    <>
      <CModal visible={visible} onClose={() => setVisible(false)}>
        <CModalHeader onClose={() => setVisible(false)}>
          <CModalTitle>Modal title</CModalTitle>
        </CModalHeader>
        <CModalBody>Woohoo, you're reading this text in a modal!</CModalBody>
        <CModalFooter>
          <CButton color="secondary" onClick={() => setVisible(false)}>
            Close
          </CButton>
          <CButton color="primary">Save changes</CButton>
        </CModalFooter>
      </CModal>
    </>
  );
};

export default Modal;

Users.js

<CTableRow v-for="item in tableItems" key={rows.userID}>
  <CTableDataCell className="text-center">{rows.userID}</CTableDataCell>
  <CTableDataCell>{rows.firstName}</CTableDataCell>
  <CTableDataCell>
    <div>{rows.lastName}</div>
  </CTableDataCell>
  <CTableDataCell className="column-overflow">{rows.email}</CTableDataCell>
  <CTableDataCell>{rows.role}</CTableDataCell>
  <CTableDataCell>{rows.createdAt}</CTableDataCell>
  <CTableDataCell>{rows.updatedAt}</CTableDataCell>

  <CTableDataCell>
    <strong>{rows.lastLogin}</strong>
  </CTableDataCell>
  <CTableDataCell>
    <CDropdown>
      <CDropdownToggle color="transparent"></CDropdownToggle>
      <CDropdownMenu>
        <CDropdownItem className="dropdown-item pointer">View</CDropdownItem>
        <CDropdownItem className="dropdown-item pointer">Edit</CDropdownItem>

        <CDropdownItem
          className="dropdown-item text-danger pointer"
          onClick={() => Modal()} <- Issue here
        >
          Delete
        </CDropdownItem>
      </CDropdownMenu>
    </CDropdown>
  </CTableDataCell>
</CTableRow>;

I would appreciate any assistance with this. Let me know if I can give any other code (I have reduced the Users.js file as it is just over 160 lines long and I don’t want to clutter, except for the row so you can get an idea of where the Delete button lives).

Thanks in advance!

>Solution :

The Modal component needs to be in the page with a visible prop controlled by the parent (and not called as a function). The CoreUI examples for CModal are a bit misleading for your use-case. I suggest using useState in your parent Users component and passing a setter callback to the Modal for the close event.

For example:

Users.js

const Users = () => {
  const [visible, setVisible] = React.useState(false);
  const [selectedUser, setSelectedUser] = React.useState(null);

  const rows = [
    { userID: "1", firstName: "Cameron", lastName: "E" },
    { userID: "2", firstName: "Steve", lastName: "G" }
  ];

  return (
    <>
      <CTable>
        {rows.map((row) => {
          return (
            <CTableRow v-for="item in tableItems" key={row.userID}>
              <CTableDataCell className="text-center">
                {row.userID}
              </CTableDataCell>
              <CTableDataCell>{row.firstName}</CTableDataCell>
              <CTableDataCell>
                <div>{row.lastName}</div>
              </CTableDataCell>
              <CTableDataCell className="column-overflow">
                {row.email}
              </CTableDataCell>
              <CTableDataCell>{row.role}</CTableDataCell>
              <CTableDataCell>{row.createdAt}</CTableDataCell>
              <CTableDataCell>{row.updatedAt}</CTableDataCell>

              <CTableDataCell>
                <strong>{row.lastLogin}</strong>
              </CTableDataCell>
              <CTableDataCell>
                <CDropdown>
                  <CDropdownToggle color="transparent">
                    Dropdown button
                  </CDropdownToggle>
                  <CDropdownMenu>
                    <CDropdownItem className="dropdown-item pointer">
                      View
                    </CDropdownItem>
                    <CDropdownItem className="dropdown-item pointer">
                      Edit
                    </CDropdownItem>

                    <CDropdownItem
                      className="dropdown-item text-danger pointer"
                      onClick={() => {
                        setSelectedUser(row);
                        setVisible(true);
                      }}
                    >
                      Delete
                    </CDropdownItem>
                  </CDropdownMenu>
                </CDropdown>
              </CTableDataCell>
            </CTableRow>
          );
        })}
      </CTable>
      <Modal
        visible={visible}
        user={selectedUser}
        onClose={() => setVisible(false)}
      />
    </>
  );
};

Modal.js

const Modal = ({ visible, onClose, user }) => {
  return (
    <>
      <CModal visible={visible} onClose={onClose}>
        <CModalHeader onClose={onClose}>
          <CModalTitle>Delete {user.firstName}?</CModalTitle>
        </CModalHeader>
        <CModalBody>
          Are you sure you want to delete {user.firstName}? (He's a good guy.)
        </CModalBody>
        <CModalFooter>
          <CButton color="secondary" onClick={onClose}>
            Yeah he is a good guy
          </CButton>
          <CButton color="primary">Nuke 'Em!</CButton>
        </CModalFooter>
      </CModal>
    </>
  );
};

Note: As an added bonus, I added an example of passing the selected user to the Modal so only one instance of the Modal component exists in the page.

Working CodeSandbox: https://codesandbox.io/s/cold-leftpad-l5ivqy?file=/src/Modal.js

Users.js Rendered
Users.js Rendered

Modal.js Rendered
Modal.js Rendered

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading