Hello I am trying to setup a contact form with React Bootstrap in a React/Next.js app. How would I reset the form after submitting it? When I added a reset handle the validation did not work anymore.
// Form validation
const [validated, setValidated] = useState(false);
// Thank you Message
const [thankYouMessage, setThankYouMessage] = useState(false);
// Form submit handler
async function handleSubmit(e) {
e.preventDefault();
e.stopPropagation();
const formData = new FormData();
Array.from(e.currentTarget.elements).forEach((field) => {
if (!field.name) return;
formData.append(field.name, field.value);
});
await fetch(
"https://domain.tld/wp-json/contact-form-7/v1/contact-forms/1234/feedback",
{
body: formData,
method: "POST",
}
)
.then((response) => response.json())
.then((response) => {
if (response.status === "mail_sent") {
setThankYouMessage(!thankYouMessage);
} else if (response.status === "mail_failed") {
alert("Message failed to send.");
}
});
setValidated(true);
}
This is the form:
<div>
<Form
noValidate
validated={validated}
onSubmit={handleSubmit}
>
<Form.Group controlId="your-name">
<Form.Control
required
type="text"
placeholder="Your name"
name="your-name"
/>
<Form.Control.Feedback type="invalid">
Please enter your name
</Form.Control.Feedback>
</Form.Group>
<Form.Group controlId="your-email">
<Form.Control
required
type="email"
placeholder="Your email address"
name="your-email"
/>
<Form.Control.Feedback type="invalid">
Please enter your email
</Form.Control.Feedback>
</Form.Group>
<Form.Group controlId="your-message">
<Form.Control
as="textarea"
cols={30}
rows={6}
placeholder="Write your message..."
name="your-message"
/>
</Form.Group>
<Button type="submit" variant="primary" size="lg">
Send Message
<span></span>
</Button>
</Form>
<Alert
variant="success"
className={thankYouMessage ? "d-block mt-3" : "d-none"}
>
Thank you for your message. It has been sent.
</Alert>
</div>
I have tried setting up a reset handle with useRef() but it did not work:
const formRef = useRef(null);
const handleReset = () => {
formRef.current.reset();
setValidated(false);
};
Then on the form added ref={formRef} and right after setValidated(true); I did handleReset(); but then the validation does not work anymore.
Any suggestions about this are welcome and any comments on the code as well!
Here's an gif of what happens when adding ref={formRef} to the Form tag and:
const formRef = useRef();
const handleReset = () => {
formRef.current.reset();
setValidated(false);
};
and in the fetch:
.then((response) => response.json())
.then((response) => {
if (response.status === "mail_sent") {
setThankYouMessage(!thankYouMessage);
handleReset();
} else if (response.status === "mail_failed") {
alert("Message failed to send.");
}
});
From what I understand, you want to get response first before resetting? e.preventDefault() is preventing the form from resetting, but by removing that, the page just reloads immediately without waiting for the response. If that is the issue that you're facing, then there are a few solutions:
Use reload (just reloads the current document).
.then((response) => {
if (response.status === "mail_sent") {
setThankYouMessage(!thankYouMessage);
} else if (response.status === "mail_failed") {
alert("Message failed to send.");
}
location.reload();
});
Use submit (just submits form without sending submit event or form validation but this is fine because you have already validated it previously).
const formRef = useRef(null);
...
.then((response) => {
if (response.status === "mail_sent") {
setThankYouMessage(!thankYouMessage);
} else if (response.status === "mail_failed") {
alert("Message failed to send.");
}
formRef.current.submit();
});
...
<Form
noValidate
validated={validated}
onSubmit={handleSubmit}
ref={formRef}
>
Use requestSubmit (same as clicking the submit button). EventListener is needed here because essentially, what you want is to disable default action by calling preventDefault first, then enable default action again after getting response. Unfortunately, there is no such convenient enableDefault function.
The flow is like this:
addEventListener with preventDefault is called (now any button clicks will not reset the form)
Fill the form and click submit button
Fetch and received response
removeEventListener with preventDefault is called (now any button clicks will reset the form)
call requestSubmit to submit the form as if the submit button is clicked, which will reset the form
const formRef = useRef(null);
...
// useCallback is needed here instead of a normal function because
// formRef will be updated every time onChange occurs because react renders again
// which will cause addEventListener/removeEventListener to not work as expected
const stopReset = useCallback((event) => {
event.preventDefault();
// stopPropagation will prevent form validation but if you really need it here
// then you need to add another event listener for handleSubmit in useEffect
// and you can remove onSubmit={handleSubmit} in Form
// event.stopPropagation();
}, []);
useEffect(() => {
formRef.current.addEventListener('submit', stopReset);
// Uncomment this only if you need stopPropagation above
// formRef.current.addEventListener('submit', handleSubmit);
},[]); // Add dependencies in the array, leave it blank if you don't have any
async function handleSubmit(e) {
// remove preventDefault and stopPropagation here
const formData = new FormData();
Array.from(e.currentTarget.elements).forEach((field) => {
if (!field.name) return;
formData.append(field.name, field.value);
});
await fetch(
"https://domain.tld/wp-json/contact-form-7/v1/contact-forms/1234/feedback",
{
body: formData,
method: "POST",
}
)
.then((response) => response.json())
.then((response) => {
if (response.status === "mail_sent") {
setThankYouMessage(!thankYouMessage);
} else if (response.status === "mail_failed") {
alert("Message failed to send.");
}
formRef.current.removeEventListener('submit', stopReset);
formRef.current.requestSubmit()
});
setValidated(true);
}
...
<Form
noValidate
validated={validated}
onSubmit={handleSubmit}
ref={formRef}
>
If you want to display your message for awhile before resetting, you can add a timer.
.then(async (response) => {
if (response.status === "mail_sent") {
setThankYouMessage(!thankYouMessage);
} else if (response.status === "mail_failed") {
alert("Message failed to send.");
}
// sleep for 10 seconds
await new Promise(r => setTimeout(r, 10000));
// call whichever method to reset
});
Related
I have tried a few variations of this, but can't seem to get it working. I have a custom hook that posts data once the user clicks a button after having chosen a value from a dropdown.
I want the button to be disabled until the fetch request returns a status of 200. Essentially I want the user to not continue to the next page until the request has completed. Here is some code:
customHook
const postData = () => {
setLoading(true);
axios({
url: -
headers: -,
method: -,
data: -,
responseType: -
})
.then((response) => {
setLoading(false);
}
})
.catch((error) => {
setLoading(false);
setError(error.response.data));
});
};
Button Component
<Button
onClick={onClickHandler}
loading={SOME STATE HERE TO ACHIEVE THIS}
>
{Continue}
</Button>
You could simply use a boolean state variable.
const [loading, setLoading] = useState(false)
const onClickHandler = () => {
setLoading(true)
performNetworkCall()
.finally(() => {
setLoading(false)
}
}
return (
<Button onClick={onClickHandler} loading={loading} >
{Continue}
</Button>
)
I've been trying to make a post request to my server(Node Js+Mongodb which runs on localhost too). Axios.post works properly on the client code, however when i try to use formData it doesn't. I can't seem to find any reason why it's not working.
It leaves no error on the console(which makes it more frustrating).
Here is the client code:
someone pls point me to what I might be doing wrong.
import React, { useState } from 'react'
import Axios from 'axios'
export default function InputData() {
const [inputName, setInputName] = useState("")
const [inputAge, setInputAge] = useState(0)
const [inputEmail, setInputEmail] = useState("")
const [userImage, setUserImage] = useState("")
const [info,setInfo] = useState("")
var bodyFormData = new FormData();
bodyFormData.append('name', inputName);
bodyFormData.append('age', inputAge);
bodyFormData.append("email", inputEmail)
const createUser = () => {
Axios.post("http://localhost:3008/createUser",
bodyFormData , { headers: { 'Content-Type': 'multipart/form-data' } }).then(function (response) {
//handle success
console.log(response);
}).catch(function (response) {
//handle error
console.log(response);
});
}
return (
<div>
<form onSubmit={createUser} encType="multipart/form-data">
<div>
<input type="text" placeholder='enter name' value={inputName} width={400} onChange={(e) => setInputName(e.target.value)} /><br/>
<input type="number" placeholder='enter age' width={400} value={inputAge} onChange={(e) => setInputAge(e.target.value)} /><br/>
<input type="email" placeholder='enter e-mail' width={400} value={inputEmail} onChange={(e) => setInputEmail(e.target.value)} /><br />
<button>Submit</button>
</div>
</form>
</div>
)
}
axios: "^0.27.2",
react: "^18.2.0"
Couple of points:
You're probably not seeing any errors (output) in the console because you're submitting the form. You can change your onSubmit handler to include preventDefault:
const createUser = (e) => {
Axios.post("http://localhost:3000/createUser", bodyFormData, { headers: { 'Content-Type': 'multipart/form-data' } })
.then(console.log)
.catch(console.error);
e.preventDefault();
}
You can also keep it as is and see the previous output by persisting the logs of your browse across requests, in Firefox this checkbox:
You should add method=post to your form
I think you will receive all the data from the event [createUser method] on submitting the form, Try removing the header If you still have problem try as below, If you still have the problem check the server side Post method Params
let data = { name: inputName, age: inputAge, email: inputEmail }
Axios.post("http://localhost:3008/createUser",data )
.then(function (response) { console.log(response); })
.catch(function (response) { console.log(response); });
I need to send form data to my database with an Axios post request, but nothing is sent.
The data I need is what is in movieId input.
Maybe the formData.append is not well written ?
const { register, handleSubmit } = useForm();
const onSubmit = data => {
const formData = new FormData();
formData.append('movieId', data.movieId);
axios.post("http://localhost:5000/addMovie", formData)
.then(response => {
console.log("Status: ", response.status);
console.log("Data: ", response.data);
}).catch(error => {
console.error('Something went wrong!', error);
});
}
return (
<div id="ModalBackground">
<div id="ModalContainer">
<button id= "closeModal" onClick= {() => {closeModal(false)}}>X</button>
<h1 id= "formTitle">Numéro du film</h1>
<form onSubmit={handleSubmit(onSubmit)} id="addMovieForm">
<input type="text" id="movieId" {...register("movieId")} required></input>
<input id= "submit" type="submit" value="Ajouter !"></input>
</form>
</div>
</div>
);
}
export default Modal```
Something is wrong there, i saw you have something specific for the handle submit, so you need to cast your call differently. Because when you do directly onSubmit={handleSubmit(onSubmit)} you are calling directly this method on every render/update
<form onSubmit={handleSubmit(onSubmit)} id="addMovieForm"
<form onSubmit={() => handleSubmit(onSubmit)} id="addMovieForm">
// if you wish to cast the event aswell
<form onSubmit={e => handleSubmit(e,onSubmit)} id="addMovieForm">
I use react hook form (https://react-hook-form.com/get-started), and the doc say that :
const { register, handleSubmit, watch, formState: { errors } } = useForm();
const onSubmit = data => console.log(data);
console.log(watch("example")); // watch input value by passing the name of it
return (
/* "handleSubmit" will validate your inputs before invoking "onSubmit" */
<form onSubmit={handleSubmit(onSubmit)}>```
So I don't know what I have to do xD
Change onSubmit={handleSubmit(onSubmit)} to onSubmit={handleSubmit} as the former is supported in HTML but not in React.
<form onSubmit={handleSubmit} id="addMovieForm">
Add a name attribute to the input field so that the key value pair for this particular input field can be stored inside FormData. This eliminates the formData.append step inside handleSubmit().
<input type="text" id="movieId" name="movieId" required></input>
You need to specify Content-Type: multipart/form-data inside the header of the POST request.
const handleSubmit = (e) => {
e.preventDefault();
// Passing form element (e.target) populates the FormData object with the names and values of the fields inside it.
const formData = new FormData(e.target);
// formData.append("movieId", data.movieId);
// To check formData because simply console.log(formData) won't work
for (let item of formData) {
console.log(item);
}
axios
.post("http://localhost:5000/addMovie", formData, {
headers: { "Content-Type": "multipart/form-data" },
})
.then((response) => {
console.log("Status: ", response.status);
console.log("Data: ", response.data);
})
.catch((error) => {
console.error("Something went wrong!", error);
});
};
I am using react for my app. I am learning post request. I found one dummy api site Mocky where I can test my post request. This is my api link .For post request I used axios. I don't know how the Mocky api works. I made post request. when I console log the input values I can the value.But when I console log the response it seems like it does not get the data. I don't see any where I am making mistake.
Here is my code:
import React, { useState } from 'react';
import { API_URLS } from '../utilities';
import axios from "axios";
export default function CreateAccount() {
const [state, setState] = useState({
"email": ``,
"password": ``,
"loading": false,
"error": ``
});
const onChangeStudent = (e) => {
setState({
...state,
[e.target.id]: e.target.value
});
};
const onSubmit = async (e) => {
e.preventDefault();
console.log(state);
const url = `https://run.mocky.io/v3/15c2b7ec-9f31-4a18-ae60-a7f41e1f39b2`;
const obj = {
"email": state.email,
"password": state.password
};
console.log(obj.email); //I can see the input value
console.log(obj.password);//I can see the input value
axios
.post(url, obj)
.then((res) => {
console.log(res.data); // it does not show the data
console.log(res);
})
.catch((error) => {
setState({
...state,
"error": error
});
});
};
return (
<div>
<form onSubmit={onSubmit}>
<input
type="text"
value={state.name}
onChange={onChangeStudent}
id="email"
required
/>
<input
type="password"
value={state.password}
onChange={onChangeStudent}
id="password"
required
/>
<button
className="btn waves-effect blue lighten-1"
type="submit"
name="action"
disabled={state.loading}
>
{state.loading ? `loading...` : `save`}
</button>
</form>
</div>
);
}
Hi can't seem to find anything wrong with what you are doing.
I tested the below and it worked for me. Try to change from .then to await. Hope this solves your problem. Check in your network tab if your request is successful and if you are sending the body.
try {
const response = await axios.post('https://run.mocky.io/v3/4b95050f-2bcc-4c78-b86e-6cac09372dce', data);
console.log("Response", response);
} catch(e) {
console.error(e);
}
I have Form
const TextForm = props => (
<Formik
initialValues = {{
text: '',
target: props.target
}}
onSubmit = {(values, { setSubmitting, resetForm }) => {
if (values.target == 'add') {
Request('POST', {"text":values.text});
resetForm({"text":""});
setSubmitting(false);
}
}}
>
{({
handleChange,
handleSubmit,
values,
}) => (
<form onSubmit={handleSubmit}>
<input type="hidden" name="target"/>
<textarea className={styles.text} value={values.text} name="text" onChange={handleChange}></textarea><br/>
<button type="submit">
Submit
</button>
</form>
)}
</Formik>
);
And data send ok. But the form doesn't clear. Why??
I also try this:
TextForm.setFieldValue('text', '');
But this doesn`t work too.
Check that the following function call is not throwing an exception:
Request('POST', {"text":values.text});
If an exception is being thrown from Request(..), then the subsequent call to resetForm(..) and setSubmitting(..) will be skipped which would be the reason for the problem you're experiencing.
Also, some improvements you might consider would be to make the following changes to your onSubmit handler:
/* Define onSubmit callback as async */
onSubmit = { async (values, { setSubmitting, resetForm }) => {
try {
if(values.target == 'add') {
/*
If request is async or returns a promise, wait
for it before resetting form
*/
await Request('POST', {"text":values.text});
resetForm({"text":""});
}
}
/*
If you want to handle errors here, do so with a
catch block like so:
catch(err) {
handleErrorHereIfYouChose(err);
}
*/
finally {
/*
Always ensure form submit state is reset, even if
unhandled is exception thrown
*/
setSubmitting(false);
}
}}
Me helped values.text = '';
onSubmit = {async (values, { setSubmitting, resetForm }) => {
try {
if (values.target == 'add') {
await fetch('http://localhost:3000/notes', {
headers: {
'Content-Type': 'application/json',
},
method: 'POST',
body: JSON.stringify({"text":values.text}),
});
values.text = '';
}
}
finally {
setSubmitting(false);
}