How to close Modal in Reactjs? - reactjs

On button click i was trying to open a model (and modal opening too) and in a same modal it contain a button and on button click i was trying to open another model (and second modal opening too), but when second modal is opening i want first model to be closed. can it be possible?
Here is my sandbox demo https://codesandbox.io/embed/dreamy-herschel-cyetn?fontsize=14&hidenavigation=1&theme=dark
const Practice = () => {
const [modalShow, setModalShow] = useState(false);
const handleSubmit = event => {
setModalShow(true);
};
return (
<div>
<Button onSubmit={handleSubmit} type="submit">
Submit
</Button>
<Modals show={modalShow} onhide={() => setModalShow(false)} />
</div>
);
};
here is my modal part
const Modals = ({ show, onhide }) => {
const [modalShowsec, setModalShowsec] = useState(false);
const Validation = () => {
setModalShowsec(true);
};
return (
<div>
<Modal show={show} onHide={onhide} size="sm" aria-labelledby="contained-modal-title-vcenter" centered>
<Modal.Header closeButton>
<Modal.Title id="contained-modal-title-vcenter">HELLO</Modal.Title>
</Modal.Header>
<Modal.Body>
<p>Hi</p>
</Modal.Body>
</Modal>
<button onClick={Validation}> Validate </button>
<Modal show={modalShowsec} onHide={() => setModalShowsec(false)}>
<Modal.Header closeButton />
<Modal.Body>
<p>Hi cool</p>
</Modal.Body>
</Modal>
</div>
);
};

Call onhide inside Validation function. This will hide the first modal.
const Validation = () => {
setModalShowsec(true)
onhide()
}

Related

Setting state to true inside a try {} block, but state automatically switching back to false on component re-render

I am trying to implement a Success Confirmation popup modal after a successful axios.delete call.
The delete is working and even console.log() works inside of my conditional rendering but I've noticed that my initial state is false, on successful delete (inside of my try block) the state changes to true but then once the component re-renders it chnages back to false, causing my popup modal to not render.
I'm not sure if the try block is the issue or the way I'm trying to render the popup modal.
Initial State
const [showSuccess, setShowSuccess] = useState(false);
axios request
const deleteService = async (id: number) => {
try {
const JWT = await getCookie("auth");
const { data } = await axios(
`/api/serviceType/${id}`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
Authorization: JWT,
},
});
setData(data);
// Success Alert Popup
setShowSuccess(true);
} catch (e) {
// Error Alert Popup
setShowAlert(true);
}
};
The alert state change inside of the catch block works as needed!
Conditional Render
// Table state update on submit
useEffect(() => {
fetchData(data);
}, [data]);
// Success Alert
if (showSuccess === true) {
return (
<>
<Modal show={show} onHide={() => {setShowSuccess(false); handleClose(); }} backdrop="static">
<Modal.Header closeButton style={{ backgroundColor: "#00E676"}}></Modal.Header>
<AlertDialog
title={"Success!"}
message={"Service Type was successfully deleted."}
/>
</Modal>
</>
)
}
if (showAlert === true) {
return (
<>
<Modal show={show} onHide={() => {setShowAlert(false); handleClose(); }} backdrop="static">
<Modal.Header closeButton style={{ backgroundColor: "#FF1744"}}></Modal.Header>
<AlertDialog
title={"Error Deleting Data"}
message={"There was an error deleting the Service."}
/>
</Modal>
</>
)
}
return (
<>
<Trash onClick={handleShow}/>
<Modal show={show} backdrop="static" onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Delete Service</Modal.Title>
</Modal.Header>
<Modal.Body>
Are you sure you want to delete this Service? This process cannot be undone.
</Modal.Body>
<Modal.Footer>
<Button variant="outline-dark" onClick={handleClose}>
Cancel
</Button>
<Button type="submit" variant="danger" onClick={() => deleteService(id)}>
Delete
</Button>
</Modal.Footer>
</Modal>
</>
);
The error modal and confirm modal work, but the success modal is not.
Entire Component
import React, { useState, useEffect } from 'react';
import { getCookie } from "../../../utils/cookies";
import axios from "axios";
import Button from 'react-bootstrap/Button';
import Modal from 'react-bootstrap/Modal';
import { Trash } from 'react-bootstrap-icons';
import AlertDialog from '../../../alerts/AlertDialog';
export default function DeleteService({ fetchData, id }) {
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
const [isLoading, setIsLoading] = useState(true);
const [data, setData] = useState([]);
// Success Dialog
const [showSuccess, setShowSuccess] = useState(false);
console.log(showSuccess)
// Error Dialog
const [showAlert, setShowAlert] = useState(false);
// DELETE
const deleteService = async (id: number) => {
try {
const JWT = await getCookie("auth");
const { data } = await axios(
`/api/serviceType/${id}`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
Authorization: JWT,
},
});
setData(data);
setIsLoading(false);
// Hides Modal on submission
setShow(false);
// Success Alert Popup
setShowSuccess(true);
} catch (e) {
setIsLoading(false);
// Error Alert Popup
setShowAlert(true);
}
};
// Table state update on submit
useEffect(() => {
fetchData(data);
}, [data]);
// Success Alert
if (showSuccess === true) {
return (
<>
<Modal show={show} onHide={() => {setShowSuccess(false); handleClose(); }} backdrop="static">
<Modal.Header closeButton style={{ backgroundColor: "#00E676"}}></Modal.Header>
<AlertDialog
title={"Success!"}
message={"Service was successfully deleted."}
/>
</Modal>
</>
)
}
if (showAlert === true) {
return (
<>
<Modal show={show} onHide={() => {setShowAlert(false); handleClose(); }} backdrop="static">
<Modal.Header closeButton style={{ backgroundColor: "#FF1744"}}></Modal.Header>
<AlertDialog
title={"Error Deleting Data"}
message={"There was an error deleting the Service."}
/>
</Modal>
</>
)
}
return (
<>
<Trash onClick={handleShow}/>
<Modal show={show} backdrop="static" onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Delete Service</Modal.Title>
</Modal.Header>
<Modal.Body>
Are you sure you want to delete this Service? This process cannot be undone.
</Modal.Body>
<Modal.Footer>
<Button variant="outline-dark" onClick={handleClose}>
Cancel
</Button>
<Button type="submit" variant="danger" onClick={() => deleteService(id)}>
Delete
</Button>
</Modal.Footer>
</Modal>
</>
);
}
You set show to false immediately before setting showSuccess to true. Remember all of your modals rely on show.
You already have separate variables to show the other modals, so why not use them?
Change show to showDelete (for clarity) and change your return to:
return (
<>
<Trash onClick={handleShow}/>
<Modal show={showDelete} backdrop="static" onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Delete Service</Modal.Title>
</Modal.Header>
<Modal.Body>
Are you sure you want to delete this Service? This process cannot be undone.
</Modal.Body>
<Modal.Footer>
<Button variant="outline-dark" onClick={handleClose}>
Cancel
</Button>
<Button type="submit" variant="danger" onClick={() => deleteService(id)}>
Delete
</Button>
</Modal.Footer>
</Modal>
<Modal show={showSuccess} onHide={() => {setShowSuccess(false); handleClose(); }} backdrop="static">
<Modal.Header closeButton style={{ backgroundColor: "#00E676"}}></Modal.Header>
<AlertDialog
title={"Success!"}
message={"Service was successfully deleted."}
/>
</Modal>
<Modal show={showAlert} onHide={() => {setShowAlert(false); handleClose(); }} backdrop="static">
<Modal.Header closeButton style={{ backgroundColor: "#FF1744"}}></Modal.Header>
<AlertDialog
title={"Error Deleting Data"}
message={"There was an error deleting the Service."}
/>
</Modal>
</>
);
Delete both if statements.
If that's too cluttered for you, you can put the modals into variables for organization.
const deleteModal =
<Modal show={showDelete} backdrop="static" onHide={handleClose}>
...
</Modal>
const successModal =
<Modal show={showSuccess} onHide={() => {setShowSuccess(false); handleClose(); }} backdrop="static">
...
</Modal>
const alertModal =
<Modal show={showAlert} onHide={() => {setShowAlert(false); handleClose(); }} backdrop="static">
...
</Modal>
return (
<>
<Trash onClick={handleShow}/>
{deleteModal}
{successModal}
{alertModal}
</>
);
In your deleteService function you call setShow(false); which causes the modal to be hidden, because you pass "show" as prop to your Modal even if showSuccess is true.
The confusion is created by variable name "show" that doesn't tell anything specific about its value, so at the end is used incorrectly

react bootstrap hook function insert to react export class

Any idea for modal component without using hooks, and use it inside another, class-based component?
function Example() {
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
return (
<>
<Button variant="primary" onClick={handleShow}>
Launch demo modal
</Button>
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Modal heading</Modal.Title>
</Modal.Header>
<Modal.Body>Woohoo, you're reading this text in a modal!</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
<Button variant="primary" onClick={handleClose}>
Save Changes
</Button>
</Modal.Footer>
</Modal>
</>
);
}
render(<Example />);
// example.js
function Example() {
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
return (
<>
<Button variant="primary" onClick={handleShow}> Launch demo modal </Button>
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Modal heading</Modal.Title>
</Modal.Header>
<Modal.Body>Woohoo, you're reading this text in a modal!</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>Close</Button>
<Button variant="primary" onClick={handleClose}>Save Changes</Button>
</Modal.Footer>
</Modal>
</>
);
}
export default Example;
// other-component.js
import Example from './example.js'
function OtherComponent() {
return (
<>
<Example />
</>
);
}

Unable to attach Event Listener to react-bootstrap modal for mouse events using ref

Unable to attach Event Listener to react-bootstrap modal for mouse events using ref
Getting TypeError: Modal.addEventListener is not a function while trying to attach event listener
Error message:
Below is sample code:
import React, { useRef,useState,useEffect } from "react";
import {Button,Modal} from 'react-bootstrap';
function ExampleModal() {
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
const cardRef = useRef(null);
useEffect(()=>{
const Modal = cardRef?.current;
// ****TypeError: Modal.addEventListener is not a function*****
Modal?.addEventListener("mousedown",mousedownhandler );
return () => {
// unsubscribe event
Modal?.removeEventListener("mousedown", mousedownhandler);
}}
,[])
const mousedownhandler=()=>{console.log('mousedown on modal')}
return (
<>
<Button variant="primary" onClick={handleShow}>
Launch demo modal
</Button>
<Modal ref={cardRef} show={show} onHide={handleClose} >
<Modal.Header closeButton>
<Modal.Title>Modal heading</Modal.Title>
</Modal.Header>
<Modal.Body>Woohoo, you're reading this text in a modal!</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
<Button variant="primary" onClick={handleClose}>
Save Changes
</Button>
</Modal.Footer>
</Modal>
</>
);
}
export default ExampleModal;

findDOMNode is deprecated in StrictMode with React.createRef()

I'm using a functional component in react to launch a popup form. I want to grab the values in the form on submission and was using the variable = React.createRef() and then a ref={variable} in the input field to retrieve them but I keep getting
Warning: findDOMNode is deprecated in Strictmode
error in the console. Is there a better way to do this?
Const AddProduct = (section) => {
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
let itemName = React.createRef();
const createProduct = () => {
console.log(itemName.current.value);
handleClose();
};
return (
<>
<a href="#" className="nav-link" onClick={handleShow}>
Add Product
</a>
<Modal show={show} onHide={handleClose}>
<Modal.Header>
<Modal.Title>Create Item</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form.Group controlId="itemName">
<Form.Label>Item Name</Form.Label>
<Form.Control type="text" name="name" ref={itemName} />
</Form.Group>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
<Button variant="primary" onClick={createProduct}>
Create
</Button>
</Modal.Footer>
</Modal>
</>
);
};

Why are my variables empty on first click Apollo Client React?

I am trying to call useMutation when I click on the "Save" button on a modal. However, the first time I click it, the variables which get sent are empty (i can see the variables in the network calls tab and all are undefined) even though when I do a console.log I can see the data.
I.e
let globalState = {};
const SessionAdd = () => {
console.log(globalState); // This always displays the correct data when I click on the "Save" button.
const [AddsessionInput, {error} ] = useMutation(addSession,{
variables: {
title:String(globalState.title),
description:String(globalState.description)
}
});
return (
<div className="AddSession">
<Button variant="primary" onClick={handleShow}>
<i className='fas fa-plus' /> Create a new Session
</Button>
<Modal show={show} onHide={handleClose} size="md">
<Modal.Header closeButton>
<Modal.Title><i className='fas fa-camera' /> Create details</Modal.Title>
</Modal.Header>
<Modal.Body> <AddSessionForm /> </Modal.Body>
<Button variant="primary" onClick={AddsessionInput}>
Save
</Button>
</Modal.Footer>
</Modal>
</div>
);
}
const AddSessionForm = () =>{
const [sessionDetails, setSessionDetails] = useState({
title:""
});
const handleSessionDetails = (evt) => {
sessionDetails[evt.target.name] = evt.target.value;
setSessionDetails(sessionDetails);
globalState = sessionDetails;
};
return(
<div>
<p><strong>Add title</strong></p>
<FormControl name="title"
onChange={handleSessionDetails}/>
<br/>
);
}
Is this the correct way to handle states when dealing with a parent component (i.e handling objects in child components from parent state)?
Thanks
I'd probably refactor it slightly:
const [AddSessionInput, {error}] = useMutation(QUERY_STRING);
const runAddSessionInput = async () => {
await AddSessionInput({ variables });
};
In your onClick:
return (
<Button variant="primary" onClick={runAddSessionInput} />
);

Resources