Formik resetting form to initial values - reactjs

I am using Formik and have the following setup below where I want to be able to reset the form when the user presses the "Cancel" button. On return to the form, all form values should be reset to initialValues which are all nulls.
<Formik
enableReinitialize
initialValues={{
...INITIAL_FORM_STATE
}}
validationSchema={ FORM_VALIDATION }
onSubmit={handleSubmit}
>
{({ values, errors, isSubmitting, isValid, setFieldValue, handleChange, resetForm }) => (
<Form>
.....
I have the following code for the Cancel button:
<Button
text="Cancel"
startIcon={<UndoIcon />}
variant="contained"
color="default"
className={classes.buttons}
component={Link}
to={'/home'}
onClick={() => {
{resetForm}
setMenu("Home")
}}
/>
After entering some text into a form field and pressing the Cancel button, which directs me back to the Home page, I then go back to the form and notice that my text is still in state within the form and not resetting.
Can anyone please assist with what I am missing.

<Button
text="Cancel"
startIcon={<UndoIcon />}
variant="contained"
color="default"
className={classes.buttons}
component={Link}
to={'/home'}
onClick={() => {
resetForm()
setMenu("Home")
}}
/>
You should use the resetForm() as a function call

you just need to set values of the input boxes to formik values:
<Formik
enableReinitialize
initialValues={{
...INITIAL_FORM_STATE
}}
validationSchema={ FORM_VALIDATION }
onSubmit={handleSubmit}
>
{({ values, errors, isSubmitting, isValid, setFieldValue, handleChange, resetForm }) => (
<input value={values.propertyName}/>
<Form>
and now resetForm should work well

You must change values through values since you dont have access to resetForm from the button.
<Button
text="Cancel"
startIcon={<UndoIcon />}
variant="contained"
color="default"
className={classes.buttons}
component={Link}
to={'/home'}
onClick={() => {
values = {
someProperty: null,
}
}}
/>

As as I see your are using Material UI. I notice that you have a "to" property in your Button component I think you have to decide either remaining on the same page and reset your form or redirecting to another page. If you want to remain on the same page I would suggest you to get rid of it because this causes some conflict. You can implement it like this:
return (<Formik
enableReinitialize
initialValues={{
...INITIAL_FORM_STATE
}}
validationSchema={ FORM_VALIDATION }
onSubmit={(values, actions) => {
actions.setSubmitting(false);
console.log("Submit form", values);
}}
>
{({ values, errors, isSubmitting, isValid, setFieldValue, handleChange, handleSubmit, resetForm }) => (
<Form onSubmit={handleSubmit}>
..... some inputs
<Button
text="Cancel"
startIcon={<UndoIcon />}
variant="contained"
color="default"
className={classes.buttons}
component={Link}
onClick={() => handleReset(resetForm)}
/>
</Form>
)}
</Formik>
);
And inside you class create a handleReset method:
const handleReset = (resetForm) => {
if (window.confirm('Reset?')) {
resetForm();
setMenu("Home");
}
};

`
const myForm = useFormik({
initialValues:{
value1:'',
value2:''
},
onSubmit:( values ) = >{
//submit data
........
//reset form after submit
myForm.resetForm()
}
)
on return
<form onSubmit={myForm.submit}>
........
<Button type="submit"/>
<Button onClick={()=>myForm.resetForm()}>Reset</Button>
</form>
`

Related

Unable to set `isSubmitting` with Formik

Edit
As it turns out, it was working all along -- the issue was because my handleLogin method was async
New sandbox:
I have a basic Form component. It passes setSubmitting as one of the available methods, and it passes isSubmitting as well. I want to disable the submit button while the form is submitting, but I'm having trouble with this.
Initially, I had a <form> element and I was trying to set setSubmitting(true) in the below part:
<form
onSubmit={(credentials) => {
setSubmitting(true); // <--
handleSubmit(credentials);
}}
>
But this didn't work. So I've tried getting rid of the <form> and changing <Button> to type="button" instead of submit, and I did,
<Button
color="primary"
disabled={isSubmitting}
fullWidth
size="large"
type="button"
variant="contained"
onClick={() => {
setSubmitting(true);
handleLogin(values);
}}
>
Submit
</Button>
But the problem with this, is that in order to do setSubmitting(false) in case of an error is that I have to do this,
onClick={() => {
setSubmitting(true);
handleLogin(values, setSubmitting); // <--
}}
And in addition to this, I have no use for onSubmit={handleLogin}, but if I remove that, Typescript complains.
There's got to be an easier way to accomplish this (without using useFormik).
What can I do here?
Here is the component:
import * as React from "react";
import { Formik } from "formik";
import { Box, Button, TextField } from "#material-ui/core";
const Form = React.memo(() => {
const handleLogin = React.useCallback(async (credentials, setSubmitting) => {
console.log(credentials);
setTimeout(() => {
setSubmitting(false);
}, 2000);
}, []);
return (
<Formik
initialValues={{
email: ""
}}
onSubmit={handleLogin} // removing this line make Typescript complain
>
{({
handleSubmit,
handleChange,
setSubmitting,
isSubmitting,
values
}) => (
<div>
<TextField
fullWidth
label="Email"
margin="normal"
name="email"
onChange={handleChange}
value={values.email}
variant="outlined"
/>
<Box sx={{ my: 2 }}>
<Button
color="primary"
disabled={isSubmitting}
fullWidth
size="large"
type="button"
variant="contained"
onClick={() => {
setSubmitting(true);
handleLogin(values, setSubmitting);
}}
>
Submit
</Button>
</Box>
</div>
)}
</Formik>
);
});
export default Form;
You forget to put the form inside your Formik component
<Formik>
{...}
<form onSubmit={handleSubmit}>
{...}
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</form>
</Formik>
so now you can use your button as submit.
demo: https://stackblitz.com/edit/react-egp1gc?file=src%2FForm.js

How can I make this Formik form work with custom Buttons I can't get the values to get to handleSubmit

I am learning React.js and I have this Codesandbox that is a a Material-Ui boilerplate. I try something now like I want the login Facebook Button when clicked to handle Facebook login.
I read the Docs and can't see any explanation for this situation. Even the Codesandbox Material-UI suggests this is a good approach.
This is what I have tried, it looks like this:
<Formik
initialValues={{
email: 'demo#devias.io',
password: 'Password123',
facebook: 'dddd',
}}
validationSchema={Yup.object().shape({
email: Yup.string().email('Must be a valid email').max(255).required('Email is required'),
password: Yup.string().max(255).required('Password is required'),
})}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
setSubmitting(false);
}, 400);
}}
>
{({ errors, handleBlur, handleChange, handleSubmit, isSubmitting, touched, values }) => (
<form onSubmit={handleSubmit}>
<Box mb={3}>
<Typography color="textPrimary" variant="h2">
Sign in
</Typography>
<Typography color="textSecondary" gutterBottom variant="body2">
Sign in on the internal platform
</Typography>
</Box>
<Grid container spacing={3}>
<Grid item xs={12} md={6}>
<Button
className={classes.Facebook}
fullWidth
startIcon={<FacebookIcon />}
onClick={handleSubmit}
size="large"
variant="contained"
name="facebook"
type="facebook"
value={values.facebook}
>
SIGN in with Facebook
</Button>
</Grid>
........
As you see on the image the:
<Button
className={classes.Facebook}
fullWidth
startIcon={<FacebookIcon />}
onClick={handleSubmit}
size="large"
variant="contained"
name="facebook"
type="facebook"
value='sdsadadadsadada'
>
SIGN in with Facebook
</Button>
I have the type="facebook" and value='sdsadadadsadada set but when I click the button the onClick={handleSubmit} does not show this values in the handleSubmit , it show the default values like:
What I want is to handle login depending on this tree types, Facebook, Google or email. Do I have to create a Button onClick separately for the Facebook and Google Buttons to handle this? What am I doing wrong?
I found the answer here.
Basically it looks like this:
function FormContainer(props) {
const [formType, setFormType] = useState(DEFAULT_FORM_TYPE);
const handlerSubmit = (methodX, methodY) => async values => {
if (formType === FORM_TYPE_X) {
return await methodX(values);
}
return await methodY(values);
};
const submitFormType = (formTypeSubmited, handleSumitType) => () => {
setFormType(formTypeSubmited, () => handlerSubmit());
};
return (
<Formik
onSubmit={handlerSubmit(props.saveToApiMethodX, props.saveToApiMethodY)}
validate={values => props.validate(formType, values)}
>
{(values, handleSubmit, errors) => (
<>
<button onClick={submitFormType(FORM_TYPE_X, handlerSubmit)}>
Method X
</button>
<button onClick={submitFormType(FORM_TYPE_Y, handlerSubmit)}>
Method Y
</button>
</>
)}
</Formik>
);
}

Formik losing selected values after button click

I have a form with some inputs of type "select". One of them works like: The user selects one service and click on "Add" button to add to a list of services, but after this click, the previously selected values (cliente, funcionario) are getting empty.
<Formik
enableReinitialize
validationSchema={formSchema}
onSubmit={(values, { resetForm }) => {
entry
? props.setSubmit(values, entry.id)
: props.setSubmit(values, resetForm);
}}
initialValues={defaultValues}
>
{({
handleSubmit,
handleChange,
values,
errors,
touched,
setFieldValue,
}) => (
<Modal
show={modalForm}
onHide={handleClose}
backdrop="static"
size="lg"
>
<Modal.Header closeButton>
<Modal.Title>Preencha o formulário</Modal.Title>
</Modal.Header>
<Form onSubmit={handleSubmit}>
<Modal.Body>
<Combobox
label="Cliente"
name="cliente"
onChange={handleChange}
value={values.cliente}
errors={errors.cliente}
options={customers}
/>
<Combobox
label="Funcionário"
name="funcionario"
errors={errors.funcionario}
onChange={async e => {
handleChange(e);
setFieldValue(
'comissao',
await loadComission(e.target.value)
);
}}
value={values.funcionario}
options={employees}
/>
<hr />
<CustomCombo
className="cbwbuton"
label="Serviço"
name="servico"
onChange={handleChange}
value={values.servico}
options={services}
>
<Button
variant="outline-primary"
onClick={() => {
console.log(values.funcionario);
addServ(values.servico);
}}
>
<i className="fa fa-plus-circle" />
</Button>
</CustomCombo>
AddServ function:
const addServ = async id => {
if (id !== '') {
try {
const newServ = await api.get(`/service/${id}`);
await setServicosRealizados([...servicosRealizados, newServ.data]);
} catch (error) {
console.log(error);
}
}
};
On screen the values "cliente" and "funcionario" still selected, but these values is empty on output json when I submit. Could someone help me with this issue?

Formik component not being rendered with react-tabs

I'm trying to use react-tabs with Formik but everytime i put the <Formik> tag, nothing gets rendered. This is what i'm trying to do:
<div className={classes.root}>
<Typography className={classes.headerText}>Editar lojista</Typography>
<Tabs>
<TabList>
<Tab>Loja e responsável</Tab>
<Tab>Segurança</Tab>
</TabList>
<Formik
initialValues={this.getInitalValues()}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
// alert(JSON.stringify(values, null, 2));
setSubmitting(false);
console.log(values);
}, 400);
}}
validationSchema={schema}>
{({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
isSubmitting
/* and other goodies */
}) => (
<form className={classes.form}>
<TabPanel>
<MainLojistaForm /> {/* this is one component */}
</TabPanel>
<TabPanel>
<SegurancaForm /> {/* this is one component */}
</TabPanel>
<div className={classes.saveContainer}>
<Button
variant="contained"
type="submit"
className={classes.button}>
Salvar
</Button>
</div>
</form>
)}
</Formik>
</Tabs>
</div>
And this is a printscreen of what it looks like without Formik:
I really dont know what i'm doing wrong. Anyone ever had this issue?
The unique error i get is from react-tabs:
1.chunk.js:252727 Warning: Failed prop type: There should be an equal number of 'Tab' and 'TabPanel' in UncontrolledTabs. Received 2 'Tab'
and 0 'TabPanel'.
What you need to do is put Formik and form wrapping Tabs.

How to reset / empty form after submit in Formik

So I've got my form. And I simply want it to be empty after the submit is successfull.
I've seen that I should be using enableReinitializing and change the value manually like : this.values.content = "".
But I'm not managing to understand where can I put this option?
<Formik
enableReinitializing //This is not working
initialValues={{
content: "",
}}
validationSchema={validAddMessageToProjectSchema(
this.props.intl.locale
)}
validateOnBlur={true}
onSubmit={ async ( values: AddMessageToProjectFormValue,
{ setSubmitting }: any
) => { await mutate({ variables: values });
setSubmitting(false);
}}
>
{({ isSubmitting, values, errors, touched, setFieldValue }) => {
return (
<Form className="addMessageToProject-form">
<div>
<FormattedMessage
id="addMessageToProject.descriptionField"
defaultMessage="Describe your post"
>
{msg => (
<Field
name="content"
placeholder={msg}
component={
TextAreaField
}
/>
)}
</FormattedMessage>
</div>
<Button
type="primary"
htmlType="submit"
className="addMessageToProject-form__submit form-submit"
disabled={isSubmitting}
>
<FormattedMessage
id="addMessageToProject.button"
defaultMessage="Send Message"
/>
</Button>
</Form>
);
}}
</Formik>
You can do it like this in onSubmit callback
onSubmit={(values, {setSubmitting, resetForm}) => {
handleSave(params, () => {
resetForm(initialValues)
})
setSubmitting(false);
}}
And this is not enableReinitializing instead use enableReinitialize

Resources