Formik losing selected values after button click - reactjs

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?

Related

Formik resetting form to initial values

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>
`

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

React Formik onSubmit Async called twice

I am trying to use async with onSubmit with following code for Formik in React
import React from "react";
import { Formik, Form, Field } from "formik";
import { Row, Col, Button } from "react-bootstrap";
const AddUser = () => {
const initialValues = {
name: "",
};
return (
<>
<Row className="h-100">
<Col xs={12} sm={1}></Col>
<Col xs={12} sm={10} className="align-self-center">
<div className="block-header px-3 py-2">Add Dataset</div>
<div className="dashboard-block dashboard-dark">
<Formik
initialValues={initialValues}
onSubmit={async (values, { setSubmitting }) => {
alert("hi");
setSubmitting(false);
}}
>
{({ isValid, submitForm, isSubmitting, values }) => {
return (
<Form>
<Field
name="name"
label="Name"
placeholder="Dataset Name"
/>
<Button
type="submit"
disabled={!isValid || isSubmitting}
className="w-100 btn btn-success"
onClick={submitForm}
>
Add Dataset
</Button>
</Form>
);
}}
</Formik>
</div>
</Col>
<Col xs={12} sm={1}></Col>
</Row>
</>
);
};
export default AddUser;
When I try to submit. It does alert 'hi' twice. When I don't use onSubmit as async then it works fine.
What am I doing wrong or is there any other way to perform async functionalities as I need to perform RestAPI calls?
Delete type="submit", because there is already an action onClick={submitForm}
<Button
type="submit"
disabled={!isValid || isSubmitting}
className="w-100 btn btn-success"
onClick={submitForm}
>
Be sure to NOT add both
onClick={formik.formik.handleSubmit}
and
<form onSubmit={formik.handleSubmit}>.
Should be one or the other.
I faced the same issue. Adding e.preventDefault() in my Form Submit Handler worked
for me.
onSubmitHandler = (e) => {
e.preventDefault();
//Handle submission
}

Change input value through click on button

I currently struggle with the button "Auto generate link". Once clicked, the Field "link" should be filled with the data "http://predefinedlink.com"
Due to the combination of Formik + Material UI used here, I struggle to achieve that.
const useStyles = makeStyles((theme) => ({[...]}));
const EventStream = ({ onSubmit, eventStream }) => {
const classes = useStyles();
return (
<Formik
initialValues={{
link: maybe(() => eventStream.link, "") || "",
}}
onSubmit={onSubmit}
validateOnBlur={false}
validateOnChange={false}
enableReinitialize
>
{({ handleSubmit, isSubmitting, dirty }) => (
<FormikForm autoComplete="off" noValidate>
<Card>
<CardContent>
<Grid container spacing={3}>
<Grid xs={12} item>
<Field name="link" label="Link" component={TextField} />
<button
onClick={console.log("Fill TextField 'link' with new data")}
>
Auto generate link »
</button>
</Grid>
</Grid>
</CardContent>
<CardActions className={classes.cardActions}>
<Button
variant="contained"
color="primary"
classes={{
root: clsx(classes.saveButton, {
[classes.saveButtonDirty]: !dirty,
}),
disabled: isSubmitting && classes.saveButtonDisabled,
}}
disabled={isSubmitting || !dirty}
onClick={handleSubmit}
>
Save
{isSubmitting && (
<CircularProgress
size={20}
thickness={5}
color="inherit"
className={classes.saveButtonProgress}
/>
)}
</Button>
</CardActions>
</Card>
</FormikForm>
)}
</Formik>
);
};
export default EventStream;
You may need to use setFieldValue
{({ handleSubmit, isSubmitting, dirty }) => (
to
{({ handleSubmit, isSubmitting, dirty, setFieldValue }) => (
The button click handler
<button
onClick={()=> {
setFieldValue ('link', 'http://predefinedlink.com')
}
}
>
Auto generate link »
</button>

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