Close Modal in UI React on Cancel button - javascript

I am following https://react.semantic-ui.com/modules/modal to create a Modal form.
I want to close the Modal when click on the Cancel button. I am restricted not to use the shorthand method suggested in the link above. How should I write the handleClose() function in order to close the Modal form?
handleClose = () => {
console.log("close")
}
render(){
return(
<Modal trigger={<Button>Upload</Button>}closeIcon>
<Modal.Content>
<p>Please upload a valid file.</p>
<Form.Input
name="upload"
label=""
type="file"
onChange={e =>
this.setState({file_data : e.target.files[0]})}
>
</Form.Input>
</Modal.Content>
<Modal.Actions>
<Button onClick = {this.handleClose}>Cancel
</Button>
<Button positive onClick = {this.handleUpload}>Upload
</Button>
</Modal.Actions>
</Modal>
);
}

I actually solved it. I initialize a variable in state which model_open : false and then declare two function for it.
handleOpen = () => {
this.setState({ model_open: true })
}
handleClose = () => {
this.setState({ model_open: false })
}
Then I just call these method based on use case.
render(){
return(
<Modal
trigger={<Button onClick={this.handleOpen}>Upload</Button>}
open={this.state.model_open}
onClose={this.handleClose}
closeIcon>
<Modal.Content>
<p>Please upload a valid file.</p>
<Form.Input
name="upload"
label=""
type="file"
onChange={e =>
this.setState({file_data : e.target.files[0]})}
>
</Form.Input>
</Modal.Content>
<Modal.Actions>
<Button onClick = {this.handleClose}>Cancel
</Button>
<Button positive onClick = {this.handleUpload}>Upload
</Button>
</Modal.Actions>
</Modal>
);
}

Related

React state change from within button's click handler is preventing form submission

Consider the code below:
function Item({name, _key})
{
console.log('rendering Item')
const [updatingName, setUpdatingName] = useState(false);
const nameInputElement = useRef();
useEffect(() => {
if (updatingName) {
nameInputElement.current.focus();
}
}, [updatingName]);
function onUpdateClick() {
setUpdatingName(true);
}
function onCancelClick() {
setUpdatingName(false);
}
return (
<div>
<input ref={nameInputElement} type="text" defaultValue={name} name="name"
disabled={!updatingName} />
{!updatingName
? <>
<button key={1} type="button" onClick={onUpdateClick}>Update</button>
<button key={2} type="submit" name="delete" value={_key}>Remove</button>
</>
: <>
<button key={3} type="submit" name="update" onClick={(e) => {setUpdatingName(false)}}>Save</button>
<button key={4} type="button" onClick={onCancelClick}>Cancel</button>
</>}
</div>
)
}
function ItemList({title})
{
return <>
<h1>{title}</h1>
<form method="post" onSubmit={(e) => {console.log('submitting');e.preventDefault()}}>
<Item name={'small'} _key={0} />
</form>
</>
}
export default ItemList;
The problem that I am facing is the click of the Save button. When it's clicked, as you can see, I trigger a state change. But at the same time, I also want the button to cause the underlying <form>'s submission.
(To check whether the form is submitted, I've prevented its default submit mechanism and instead gone with a simple log.)
However, it seems to be the case that when the state change is performed from within the onClick handler of the Save button, it ceases to submit the form. If I remove the state change from within the handler, it then does submit the form.
Why is this happening?
Live CodeSandbox demo
When you call setUpdatingName(false) in save button's click handler, the button is removed from the DOM before submitting. You can add the logic for showing the buttons in ItemList, like below:
function ItemList({ title }) {
const [updatingName, setUpdatingName] = useState(false);
return (
<>
<h1>{title}</h1>
<form
method="post"
onSubmit={(e) => {
e.preventDefault();
setUpdatingName(false);
console.log("submitting");
}}
>
<Item
name={"small"}
_key={0}
updatingName={updatingName}
setUpdatingName={setUpdatingName}
/>
</form>
</>
);
}
export default ItemList;
function Item({ name, _key, updatingName, setUpdatingName }) {
console.log("rendering Item");
const nameInputElement = useRef();
useEffect(() => {
if (updatingName) {
nameInputElement.current.focus();
}
}, [updatingName]);
function onUpdateClick() {
setUpdatingName(true);
}
function onCancelClick() {
setUpdatingName(false);
}
return (
<div>
<input
ref={nameInputElement}
type="text"
defaultValue={name}
name="name"
disabled={!updatingName}
/>
{!updatingName ? (
<>
<button key={1} type="button" onClick={onUpdateClick}>
Update
</button>
<button key={2} type="submit" name="delete" value={_key}>
Remove
</button>
</>
) : (
<>
<button key={3} type="submit" name="update">
Save
</button>
<button key={4} type="button" onClick={onCancelClick}>
Cancel
</button>
</>
)}
</div>
);
}
Also, you could use useTransition to ask React to delay the state update, so the submission happens first:
function Item({ name, _key }) {
console.log("rendering Item");
const [isPending, startTransition] = useTransition();
const [updatingName, setUpdatingName] = useState(false);
const nameInputElement = useRef();
useEffect(() => {
if (updatingName) {
nameInputElement.current.focus();
}
}, [updatingName]);
function onUpdateClick() {
setUpdatingName(true);
}
function onCancelClick() {
setUpdatingName(false);
}
return (
<div>
<input
ref={nameInputElement}
type="text"
defaultValue={name}
name="name"
disabled={!updatingName}
/>
{!updatingName ? (
<>
<button key={1} type="button" onClick={onUpdateClick}>
Update
</button>
<button key={2} type="submit" name="delete" value={_key}>
Remove
</button>
</>
) : (
<>
<button
key={3}
type="submit"
name="update"
onClick={(e) => {
startTransition(() => setUpdatingName(false));
}}
>
Save
</button>
<button key={4} type="button" onClick={onCancelClick}>
Cancel
</button>
</>
)}
</div>
);
}

How can I connect between my form and modal?

I made a form project with react. My form is working well for now but I want add bootstrap modal to my form.
When I click the enter button, I want to show a modal. I found modal example on the web but I can't establish connection between form and modal. This is my form
import React from "react";
import { useState } from "react";
const Contact = () => {
const [showModal, setShowModal] = useState(false);
const [inputValue, setInputValue] = useState("");
const [emailValue, setEmailValue] = useState("");
const [phoneNumberValue, setPhoneValue] = useState("");
const [countryValue, setCountryValue] = useState("");
const buttonOnClick = () => {
if (inputValue === "" || emailValue === "" || phoneNumberValue === "") {
setShowModal(false)
} else {
setShowModal(true)
setInputValue("")
}
console.log(`Form submitted, ${showModal}`);
}
return (
<div className="main">
<form >
<div className="baslik">
<div className="container center">
<h1>Contact Form</h1>
</div>
</div>
<div className="field" >
<label className="text"> Name And Surname: </label>
<input type="text" className="form" placeholder="Kerem Kurt" required value={inputValue} onChange={(e) => setInputValue(e.target.value)} />
</div>
<div className="field">
<label className="text"> E-mail: </label>
<input type="email" className="form" placeholder="udenditfy#gmail.com" required value={emailValue} onChange={(e) => setEmailValue(e.target.value)} />
</div>
<div className="field">
<label className="text"> Phone Number: </label>
<input type="tel" className="form" pattern="[0-9]*" placeholder="+905373199437" required value={phoneNumberValue} onChange={(e) => setPhoneValue(e.target.value)} />
</div>
<div className="field">
<label className="text" required > Country: </label>
<select className="form" placeholder="Turkiye" required value={countryValue} onChange={(e) => setCountryValue(e.target.value)}>
<option value="Turkiye">Turkiye</option>
<option value="Azerbaijan">Azerbaijan</option>
<option value="Japan">Japan</option>
<option value="Serbia">Serbia</option>
<option value="France">France</option>
</select>
</div>
<button type="button" className="button" onClick={() => buttonOnClick()}> Enter </button>
</form>
</div>
);
};
export default Contact;
And this is modal codes;
import React, { useState } from 'react';
import Button from 'react-bootstrap/Button';
import Modal from 'react-bootstrap/Modal';
function Example() {
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
return (
<>
<Button variant="primary" onClick={handleShow}>
Launch static backdrop modal
</Button>
<Modal
show={show}
onHide={handleClose}
backdrop="static"
keyboard={false}
>
<Modal.Header closeButton>
<Modal.Title>Modal title</Modal.Title>
</Modal.Header>
<Modal.Body>
I will not close if you click outside me. Don't even try to press
escape key.
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
<Button variant="primary">Understood</Button>
</Modal.Footer>
</Modal>
</>
);
}
render(<Example />);
If you want to open your modal after the event "click" in your Form component, you have to import the modal in your form.
For example, your Form is in a component called "Form.jsx" and Modal is in "Modal.jsx" :
Inside Form.jsx, you must import your Modal, move the "show" state into your Form.jsx and pass it in Modal props, just like that :
import Modal from '/path/to/Modal.jsx'
const [show, setShow] = useState(false);
<form>
{children}
</form>
<Modal show={show} setShow={setShow}/>
Inside your Modal.jsx, just change a few things :
function Modal(props){
// remove the show State
// Remove the Button with "handleShow" function.
const handleClose = () => props.setShow(false);
<Modal show={props.show}>
<Button onClick={handleClose}>Close</Button>
</Modal>
}
Welcome to world of react development!
Your question is a classic question about sharing state between components. This is what you refer to as "connection" between components.
The solution is generally referred to as "lifting state up". I highly recommend reading through that if you haven't already.
Example:
import React from 'react';
import ReactDOM from 'react-dom/client';
import { useState } from "react";
import Button from 'react-bootstrap/Button';
import Modal from 'react-bootstrap/Modal';
const root = ReactDOM.createRoot(document.getElementById('root'));
const Contact = ({toggleShow}) => {
return (
<div className="main">
<form >
<button type="button" className="button" onClick={() => toggleShow()}> Show Modal </button>
</form>
</div>
);
};
const MyModal = ({show, toggleShow}) => {
return (
<>
<Modal
show={show}
onHide={toggleShow}
backdrop="static"
keyboard={false}
>
<Button variant="secondary" onClick={toggleShow}>
Close
</Button>
</Modal>
</>
);
}
const App = () => {
const [show, setShow] = useState(false);
const toggleShow = () => setShow(!show);
return (
<>
<Contact toggleShow={toggleShow}/>
<MyModal show={show} toggleShow={toggleShow}/>
</>
)
}
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
Explanation:
The general idea is to share the show state of the Modal as well as the state toggler toggleShow() between our <Contact> and <MyModal> components.
We can easily achieve this:
create a new parent component <App> (the name is arbitrary) where we define the show state and the toggler function.
pass the state and toggler into the modal: <MyModal state={state} toggleShow={toggleShow} />.
the form only needs the toggler: <Form toggleShow={toggleShow} />
Note that toggleShow can also be split into separate handleShow and handleClose function, but this approach saves us a few lines.

i want to disabled button if textbox null in react

return (
{jobstate.jobs.map((data,i) =>{
<form>
<input type="text" placeholder="Post a comment" onChange={(e) => jobcmthandler(e,data._id,i) } />
<button type="button" onClick={postcmt} >Send</button>
</form>
})}
)
I generate dynamic HTML using the map function and I want to disabled button if text null for induvial form and also how to get text value on button click in react js
I can't really see why you'd want to do this but here you go (example):
import React, { useState } from "react";
export default function App() {
return ["Name", "Age"].map((label) => <Form label={label} />);
}
function Form({ label }) {
const [readValue, writeValue] = useState("");
return (
<form>
<label>{label}</label>
<input
type="text"
placeholder="Post a comment"
onChange={(e) => writeValue(e.target.value)}
value={readValue}
/>
<button
type="button"
onClick={() => console.log("Submit")}
disabled={readValue === ""}
>
Send
</button>
</form>
);
}

Formik Reset callback creates recursive issue

I have a very simple formik setup where I need to pass the new initial values when users press reset form button. I am following doc but I end up creating recursive issue.
formReset() is passed to formik as a param of onReset. The function is called but I am not sure where is the recursion happening.
Here is a codesandbox for your convenient. Change form value then try to reset the form.
App.js
// Helper styles for demo
import "./helper.css";
import { MoreResources, DisplayFormikState } from "./helper";
import React from "react";
import { render } from "react-dom";
import { Formik } from "formik";
import * as Yup from "yup";
const formReset = (_, {resetForm}) => {
resetForm({email: ''});
}
const App = () => (
<div className="app">
<h1>
Basic{" "}
<a
href="https://github.com/jaredpalmer/formik"
target="_blank"
rel="noopener noreferrer"
>
Formik
</a>{" "}
Demo
</h1>
<Formik
initialValues={{ email: "populate#test.com" }}
onSubmit={async values => {
await new Promise(resolve => setTimeout(resolve, 500));
alert(JSON.stringify(values, null, 2));
}}
onReset={formReset}
validationSchema={Yup.object().shape({
email: Yup.string()
.email()
.required("Required")
})}
>
{props => {
const {
values,
touched,
errors,
dirty,
isSubmitting,
handleChange,
handleBlur,
handleSubmit,
handleReset
} = props;
return (
<form onSubmit={handleSubmit}>
<label htmlFor="email" style={{ display: "block" }}>
Email
</label>
<input
id="email"
placeholder="Enter your email"
type="text"
value={values.email}
onChange={handleChange}
onBlur={handleBlur}
className={
errors.email && touched.email
? "text-input error"
: "text-input"
}
/>
{errors.email && touched.email && (
<div className="input-feedback">{errors.email}</div>
)}
<button
type="button"
className="outline"
onClick={handleReset}
disabled={!dirty || isSubmitting}
>
Reset
</button>
<button type="submit" disabled={isSubmitting}>
Submit
</button>
<DisplayFormikState {...props} />
</form>
);
}}
</Formik>
<MoreResources />
</div>
);
render(<App />, document.getElementById("root"));
Edit:
So... a better option would be to use initialValues in useState and pass enableReinitialize and change the state to "reset" the form. It's more easy than trying to use resetForm.
You don't need to pass a function to onReset and call resetForm, you can do that by just pass the type reset to the button and have the Form component instead of normal html form tag.
The Form component will handle the handleReset that will be trigger when you have a button with type="reset".
<Form>
{/* other components */}
<button
type="reset"
className="outline"
disabled={!dirty || isSubmitting}
>
Reset
</button>
</Form>
Here is a working example.

Bootstrap Modal goes blank after button click

I am trying to call a Modal function. When I click to view it, it doesn't render and the page goes blank(white).
This is the code for
BootstrapModal :
class BootstrapModal extends React.Component{
constructor(){
super();
this.state = {
showHide : false
}
}
handleModalShowHide() {
console.log("hitting");
this.setState({ showHide: !this.state.showHide })
}
render(){
return(
<div>
<Button variant="third" id="btn-third" onClick={() => this.handleModalShowHide()}>
Send Email
</Button>
<Modal show={this.state.showHide}>
<Modal.Header closeButton onClick={() => this.handleModalShowHide()}>
<Modal.Title>Email Chart To User</Modal.Title>
</Modal.Header>
<Modal.Body>
<FormGroup>
<Modal.Label>Email address</Modal.Label>
<Modal.Input
type="email"
placeholder="Email"
/>
</FormGroup>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={() => this.handleModalShowHide()}>
Cancel
</Button>
<Button variant="primary" onClick={() => this.handleModalShowHide()}>
Send
</Button>
</Modal.Footer>
</Modal>
</div>
)
}
}
export default BootstrapModal;
Any ideas on why this is happening? Any suggestions would be gladly appreciated.
I think your problem is that you have not binded the handleModalShowHide() function. You can aviod having to do thst using an arrow function:
handleModalShowHide = () => {
Code here
}
I had to change
<FormGroup>
<Modal.Label>Email address</Modal.Label>
<Modal.Input
type="email"
placeholder="Email"
/>
</FormGroup>
To
<FormGroup>
<label for="message-text" class="col-form-label">Email Adress:</label>
<input type="text" class="form-control" id="recipient-name"></input>
</FormGroup>
After changing this, the Modal successfully rendered.

Categories