Formik Default Values UseEffect - reactjs

I am trying to prepopulate a Formik with JSON data. The data appears fine and it is returned. I have two issues.
I am using ASP.NET Core as the back end. Should I use values or initialValues as the variable? When I use initialValues, I get assign fields. The labels are still populated.
The labels are still populated, after I send a default value. All the fields are read only and I cannot edit them:
Here is my code:
function OrdersToReporting() {
const [initialValues, setInitialValues] = useState<OrdersToReportingViewModels>({ });
useEffect(() => {
agent.Settings.getOrdersSettings().then((userList) => {
let solutionName = (new URLSearchParams(window.location.search)).get("SolutionName");
let solutionWebsite = (new URLSearchParams(window.location.search)).get("SolutionWebsite");
userList.data.SolutionName = solutionName;
userList.data.SolutionWebsite = solutionWebsite;
setInitialValues(userList.data);
});
}, []);
const handleSubmit = async (
values: any,
{ resetForm, setErrors, setStatus, setSubmitting }: any
) => {
try {
await timeOut(1500);
agent.Settings.saveOrdersSettings(values);
resetForm();
setStatus({ sent: true });
setSubmitting(false);
} catch (error: any) {
setStatus({ sent: false });
setErrors({ submit: error.message });
setSubmitting(false);
}
};
return (
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={handleSubmit}
>
{({
errors,
handleBlur,
handleChange,
handleSubmit,
isSubmitting,
touched,
values,
status,
}) => (
{isSubmitting ? (
<Box display="flex" justifyContent="center" my={6}>
<CircularProgress />
</Box>
) : (
<form onSubmit={handleSubmit}>
<Grid container spacing={6}>
<Grid item md={6}>
<TextField
name="SolutionName"
label="Solution Name"
value={initialValues.SolutionName}
fullWidth
onBlur={handleBlur}
onChange={handleChange}
variant="outlined"
my={2}
/>
<TextField
name="SolutionWebsite"
label="Solution Website"
value={initialValues.SolutionWebsite}
fullWidth
onBlur={handleBlur}
onChange={handleChange}
variant="outlined"
my={2}
/>
<TextField
name="lastDownloadUtc"
label="Last Download Date Start"
value={initialValues.LastDownloadUtc}
fullWidth
onBlur={handleBlur}
onChange={handleChange}
variant="outlined"
my={2}
/>
</Grid>
<Grid item md={6}>
<TextField
name="lastDownloadUtcEnd"
label="Last Download Date End"
value={initialValues.LastDownloadUtcEnd}
fullWidth
onBlur={handleBlur}
onChange={handleChange}
variant="outlined"
my={2}
/>
</Grid>
</Grid>
<Button
type="submit"
variant="contained"
color="primary"
mt={3}
>
Save changes
</Button>
</form>
)}
)}
</Formik>
);
}

For your questions,
You should use initialValues to assign default values to your fields.
since you are getting the data from some function, there might be a delay in setting initialValues. So pass enableReinitialize={true} in formik props.
You were not able to change the values because you set
value={initialValues.fieldName} // always value will be this unless you change initialValues state
for every textfield. Always this will be same even if you edit.
Just remove the value property formik will handle it by default.

Related

Formik value is undefined

Why I can't get the data every time I change the field? can somebody help me to configure this out? did I miss something in my code? I just want that if the user clicks the submit, it will capture what I inputted in TextField and Select
const [ author, setAuthor] = useState('');
const [ datef, setDateF] = useState('');
const [ datet, setDateT] = useState('');
const handleChangeAuthor = (event) => {
console.log("handleChangeAuthor: ", event)
setAuthor(name)
};
const handleChangesetDateF = (event) => {
console.log("handleChangesetDateF: ", event)
setDateF(name)
};
const handleChangesetDateT = (event) => {
console.log("handleChangesetDateT: ", event)
setDateT(name)
};
const handleSubmit= async(valuesToSubmit) =>
{
console.log("valuesToSubmit: ", valuesToSubmit)
}
............
<Formik
initialValues={{
strdatefrom:datef,
strdateto:datet,
intuserauthorid:author,
intfmdocumentclassificationsid:selecteddocClassification,
intlimit:"100",
intoffset:"0"
}}
onSubmit={(values) =>{ console.log("submit"); handleSubmit(values)}}
>
{({ handleChange, handleBlur, handleSubmit, values, errors, isValid,touched,setFieldValue }) => (
<>
<Grid container>
<Grid xs={12} className={classes.grid}>
<TextField
id="date"
label="Date from"
type="date"
name="datet"
onChange={handleChangesetDateF(value.datet)}
defaultValue="2017-05-24"
name="datef"
className={classes.textField}/>
</Grid>
<Grid xs={12} className={classes.grid}>
<TextField
id="date"
label="Date to"
type="date"
name="datef"
onChange={handleChangesetDateT(value.datef)}
defaultValue="2017-05-24"
className={classes.textField}/>
</Grid>
<Grid xs={12} className={classes.grid}>
<FormControl variant="outlined" className={classes.formControl}>
<InputLabel htmlFor="outlined-age-native-simple">Author</InputLabel>
<Select
name="author"
value={author}
onChange={handleChangeAuthor(value.author)}
label="Author">
{users}
</Select>
</FormControl>
</Grid>
</>
)}
</Formik>
from this line please ignore this message, I do this message so that i
can submit a question here
You Dont have to use a local state for formik, formik can manage the state internally so you will have to do something like this to update the value.
<TextField
id="date"
label="Date from"
type="date"
name="datet"
onChange={event=>setFieldValue('datet',event.target.value)}
defaultValue="2017-05-24"
name="datef"
className={classes.textField}
value={values.datet}/>
The setFieldValue in formik can update the formik state which you can retrieve in handlesubmit call

TypeError: Cannot read property 'setFieldValue' of undefined. Formik doesn't recognise setFieldValue

I'm trying to create an image upload on my form. The problem is when I try to change the value to the actual uploaded file. I am trying to use setFieldValue, but it says it is undefined. Below is the code. Any ideas why it is undefined? I thought it comes with Formik.
import { Formik } from 'formik';
const AddProduct = (props) => {
return (
<Formik
initialValues={{
serviceImage: null
}}
onSubmit={(values) => {
console.log(values);
}}
>
{({
errors,
handleBlur,
handleChange,
handleSubmit,
setFieldValue,
isSubmitting,
touched,
values,
formProps
}) => (
<form onSubmit={handleSubmit}>
<TextField
error={Boolean(touched.serviceName && errors.serviceName)}
fullWidth
helperText={touched.serviceName && errors.serviceName}
label="Service name"
margin="normal"
name="serviceName"
onBlur={handleBlur}
onChange={handleChange}
value={values.serviceName}
/>
<Button>
<input
id="file"
name="serviceImage"
value={values.serviceImage}
type="file"
onChange={(event) => formProps.setFieldValue('serviceImage', event.target)
}
/>
Add an Image
</Button>
<Button
type="submit" >
Post this service on the Events Platform
</Button>
</form>
)}
</Formik>
);
};
You already declare setFieldValue in your formik callback function
So change it to:
<input
id="file"
name="serviceImage"
value={values.serviceImage}
type="file"
onChange={event => setFieldValue('serviceImage', event.currentTarget.files[0])}
/>;

How disable the auto reset form on submit in formik?

I have a form that i'm controlling by formik, when i fill all the fields and press the buttom submit, the function onSubmit is called and my form have this values reseted.
Sometimes my data is incorrect (like a duplicate email) and i need to persist this data.
How i can do this?
This is my code:
const schema = Yup.object().shape({
login: Yup.string()
.email('Email não possui formato válido')
.required('Informe o email!'),
password: Yup.string().required('Informe a senha!'),
})
const formik = useFormik({
initialValues: {
login: '', password: '', inactive: false
},
validationSchema: schema,
onSubmit: values => {
registerUser(values)
}
})
return (
<form onSubmit={formik.handleSubmit} className={classes.form} noValidate>
<Grid container spacing={3}>
<Grid item xs={12}>
<Typography className={classes.observation} component="h6">* Necessário preenchimento do cadastro geral para liberar permissão de telas</Typography>
</Grid>
<Grid item xs={5}>
<TextField
value={formik.values.login}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
helperText={formik.touched.login ? formik.errors.login : ""}
error={formik.touched.login && Boolean(formik.errors.login)}
variant="outlined"
margin="normal"
required
fullWidth
id="email"
label="E-mail"
name="login"
autoComplete="email"
/>
</Grid>
<Grid item xs={5}>
<TextField
value={formik.values.password}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
helperText={formik.touched.password ? formik.errors.password : ""}
error={formik.touched.password && Boolean(formik.errors.password)}
variant="outlined"
margin="normal"
required
fullWidth
type="password"
id="password"
label="Senha"
name="password"
/>
</Grid>
<Grid item xs={2}>
<FormControlLabel
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.inactive}
control={<Switch color="primary" />}
label="Inativo"
labelPlacement="top"
/>
</Grid>
<Grid item xs={3}>
<Button fullWidth
variant="contained"
color="primary"
type="submit"
>
Cadastrar
</Button>
</Grid>
</Grid>
</form>
);
Use the Form from formik, and the default is to not reset on submit:
import { Formik, Form } from "formik";
function DemoComp(){
return(
<Formik
initialValues={{ fieldOneVal: "" }}
onSubmit={async (formsData, {setSubmitting, resetForm}) => {
setSubmitting(true)
// async request
// --> if wanted to reset on submit: resetForm();
console.log(formsData)
setSubmitting(false)
}}
>
{({ values, isSubmitting, handleChange, handleBlur, handleSubmit }) => (
<Form>
<input
type="text"
name="fieldOneVal"
value={values.fieldOneVal}
onChange={handleChange}
onBlur={handleBlur}
/>
<button type="submit">Submit</button>
</Form>
)}
</Formik>
)
}
You need to update the following line:
<form onSubmit={(e) => { e.preventDefault(); formik.handleSubmit(e)}} className={classes.form} noValidate>
You need to define the function to be async and as async response handling is not mention in your code so it's hard to give exact solution
<Formik
initialValues={{ fieldOneVal: formvalues.fieldOneVal }}
onSubmit={async (values, { resetForm }) => {
// setFormvalues(({fieldOneVal:values.fieldOneval}) don't know why you're manipulating state
const resp=await someAsyncFunc()
if (resp){
reset the state to initial values}
else{
pop up modal display with errors}
}}
>
I faced the same problem formik resetting the form before i get a response from the server.This solution helped me.
import { Formik, Form } from "formik";
function DemoComp(){
const [formvalues,setFormvalues]= useState({
{ fieldOneVal: "" }
)
return(
<Formik
initialValues={{ fieldOneVal: formvalues.fieldOneVal }}
onSubmit={(values, { resetForm }) => {
setFormvalues(({fieldOneVal:values.fieldOneval})
// async request
if sucess{
reset the state to initial values}
else{
pop up modal display with errors}
}}
>
{({ values, isSubmitting, handleChange, handleBlur, handleSubmit }) => (
<Form>
<input
type="text"
name="fieldOneVal"
value={values.fieldOneVal}
onChange={handleChange}
onBlur={handleBlur}
/>
<button type="submit">Submit</button>
</Form>
)}
</Formik>
)
}

Formik values empty

I have the following Formik form
<Formik
initialValues={{
email: '',
password: ''
}}
onSubmit={(values, { setSubmitting }) => {
console.log(JSON.stringify(values));
setSubmitting(true);
fetch('/login', {
method: 'POST',
body: JSON.stringify(values),
headers: {
'Content-Type': 'application/json'
}
})
.then(res => res.json())
.then(response => {
console.log(response);
setSubmitting(false);
if (!response.success) return showAlert();
login(response.user);
history.push('/');
})
.catch(console.log);
}}
>
{({ isSubmitting }) => (
<Form className={classes.form}>
<TextField
required
variant="outlined"
margin="normal"
fullWidth
label="Email"
name="email"
autoFocus
/>
<TextField
required
variant="outlined"
margin="normal"
fullWidth
name="password"
label="Wachtwoord"
type="password"
/>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
disabled={isSubmitting}
>
Log in
</Button>
<Grid container>
<Grid item xs>
<Link href="/register" variant="body2">
{'Nog geen account? Registreer nu!'}
</Link>
</Grid>
</Grid>
</Form>
)}
</Formik>
For some reason the values in the onSubmit are empty, how can I set it to the values inside the form? The only difference between this form and another one I got to work is that this one does not have a validation schema but I can not imagine that is required
You should take a look at the example in formik's docs.
TextField isn't connect to Formik. When the value of TextField changes, Formik don't change, you need Field (import { Field } from 'formik') that will render TextField.
Example for email
<Field
name="email"
render={({ field /* _form */ }) => (
<TextField
required
variant="outlined"
margin="normal"
fullWidth
label="Email"
autoFocus
{...field}
/>
)}
/>
If you are using a external input, you should use this way.
You need to pass this
onChangeText={handleChange('email')}
onBlur={handleBlur('email')}
value={values.email}
to the Textinput, and for Password aswell.
Your Textinput doesn't track any changes or submission.
Check here

formik fields are not getting value

I'm using Formik in my React and redux project, but Formik fields are not getting value and onChange field function not working!
this form is for editing a customer. I'm using Formik in another part of project and i don't have a problem. I don't know what to do?
<Formik
initialValues={props.selectedCustomer.id ? props.selectedCustomer : emptyCustomer}
validationSchema={customerValidationSchema}
onSubmit={async (values: ICustomer, actions: FormikActions<any>) => {
console.log(values)
try {
await postCustomer(values)
props.selectedCustomer.id ? enqueueSnackbar('success') : enqueueSnackbar('fail')
actions.resetForm()
getCustomers(pageNum, pageSize)
setAddDialog(false)
}
catch (error) {
enqueueSnackbar(error, { variant: 'default' })
}
}}
>
{() => (
<Form id="addCustomerForm">
<div id="addCustomerDiv" className={clsx({
[classes.noDisplay]: !addDialog
})}>
<Grid style={{marginRight: '0.5rem'}} container spacing={5}>
<Grid item xs={2}>
<Field
name="firstName"
render={({ field, form }: FieldProps<ICustomer>) => (
<TextField
margin="dense"
id="firstName"
label="firstName"
fullWidth
{...field}
error={form.errors.firstName && form.touched.firstName ? true : false}
/>
)}
/>
</Grid>
<Button
type='submit'
form="addCustomerForm"
color="primary"
variant="contained"
style={{marginTop: '3rem'}}
className={clsx({
[classes.noDisplay]: !addDialog
})}
>
submit
</Button>
</Grid>
</Grid>
</div>
</Form>
)}
</Formik>
what is the problem?
I added enableReinitialize in Formik component and it worked.

Resources