Formik initialValues and onSubmit issues - reactjs

I am having a couple of issues with my Formik Form.
If I use defaultValue={location.fname} on the <TextField> I can type in the field,
but on submit the newly typed values do not appear in the alert.
If I use value={location.fname} on the <TextField> I can't type in the field.
What am I doing wrong? I would like to be able to type into the field to update the value AND get the new value onSubmit.
let formik = useFormik({
initialValues: {
fname: person.fname,
lname: person.lname,
address: person.address,
city: person.city,
},
enableReinitialize:true,
validateOnChange: false,
validateOnBlur: false,
validationSchema: validationSchema,
onSubmit: values => {
alert(JSON.stringify(values, null, 2));
},
});
...
<TextField
id="fname"
name="fname"
variant="outlined"
defaultValue={location.fname}
onChange={formik.setFieldValue}
error={formik.touched.fname && Boolean(formik.errors.fname)}
helperText={formik.touched.fname && formik.errors.fname} />

Change the defaultValue from location.fname to formik.values.fname as you are already passing the values to formik using initialValues. Also change the onChange from formik.setFieldValue to formik.handleChange and let formik handle the form state through the input name, finally add onBlur={formik.handleBlur} so that formik can know when your input field is touched.

Related

React using Formik does not clear the data value in Material UI form

I'm using formik.resetForm() to remove values from text fields in a form after submitting the data.
...
const handleSubmitProduct = async (values: Object, resetForm: any) => {
... code to handle my form data ...
resetForm()
if (response.ok) {
console.debug(response.status)
} else {
console.error(response)
}
}
const validate = (values: Object) => {
const errors: any = {}
if (!values.product_name) {
errors.product_name = "Include name"
}
return errors
}
... initialValues defined ...
const formik = useFormik({
initialValues: initialValues,
validate,
onSubmit: (values: Object, { resetForm }) => {
console.debug(JSON.stringify(values, null, 2))
handleSubmitProduct(values, resetForm)
},
})
return (
<FormLabel>Display name</FormLabel>
<TextField
onChange={formik.handleChange}
id="product_name"
onBlur={formik.handleBlur}
error={formik.touched.product_name && Boolean(formik.errors.product_name)}
helperText={formik.touched.product_name && formik.errors.product_name}
/>
<Button onClick={() => formik.handleSubmit()} variant="contained">
Submit
</Button>
)
I know there are many other questions like this but mine is different where I know the underlying Formik resources for values, errors, touched have been cleared but the values are still present in the text boxes.
The issue is I know the underlying Formik objects are cleared because after I submit, the validation triggers and prompts me like there is no value in the text field.
I've tried
resetForm({values: {initialValues}}) has the same result
resetForm(initialValues) has the same result
Use action.resetForm({values: {initialValues}}) in the onSubmit() which same result
https://codesandbox.io/s/mui-formik-fr93hm?file=/src/MyComponent.js but this approach uses the <Formik /> as opposed to useFormik which would change up my entire page but I'm in process to try anyway
I think the problem is that value of TextField is not value of formik. so the TextField is not controlled and by chaning value of formik it won't change.
assigning value of formik to it will do what you want
value={formik.values.firstName}
like this :
<TextField
onChange={formik.handleChange}
id="product_name"
value={formik.values.firstName}
onBlur={formik.handleBlur}
error={formik.touched.product_name && Boolean(formik.errors.product_name)}
helperText={formik.touched.product_name && formik.errors.product_name}
/>

Formik values didnt update after change

I cant get the values from disabled input after fetch data. I think cause i put 2 condition in my input value component like this. is there a way to run properly from this code. i use formik to handle my form
<Input
disabled={true}
value={ProfileData ? moment(ProfileData.BirthDate).format('DD MMMM YYYY') : '' && formik.values.formA.ValueDesc5}
type="text"
name="formA.ValueDesc5"
onBlur={formik.handleBlur}
onChange={formik.handleChange}
/>
ProfileData is a state that contain User Profile
In my case, I use Next JS 13.0.4 + Chakra UI + Formik 2.2.9 and I face the same issues as yours.
I use SWR to fetch data from my server:
const fetcher = async (id: string): Promise<Course> => {
return (await findCourseById(id)) as Course;
...
const { data: dbCourse, error } = useSWR(
urlToServer,
() => fetcher(id),
{
refreshInterval: 1000,
},
);
};
The key to solve the problem is that we need to re-initialize the default values of the form. I use useFormik hook, and it looks like this:
const formik = useFormik({
initialValues: {
name: dbCourse?.name as string,
description: dbCourse?.description as string,
},
validationSchema: updateCourseSchema,
enableReinitialize: true, // <=== check this line
onSubmit: async (values) => {
console.log(values);
},
});
Let me know if it helps!

Hook managed state on Form does not update in parent component

I have a form:
<FieldLabel label='Label'>
<Textfield
value={formState.name}
onChange={name => setFormState({ ...formState, name })}
name="someName"/>
</FieldLabel>
<FieldLabel label='Description'>
<Textarea
value={formState.description}
onChange={description => setFormState({ ...formState, description}}
name="someDesc"/>
</FieldLabel>
This form is 'dumb' meaning it gets its formState from a parent and dispatches setFormState when input is changed.
In the parent component it looks like:
<MyForm
formState={formState}
setFormState={setFormState} />
where formState and setFormState are hooks:
const initialFormState: FormState = {
name: '',
description: '',
}
const [formState, setFormState] = useState<FormState>({ ...initialFormState });
However, the state does not change, nor am I able to write anything into the inputs on the Form. When I click submit the initial state is logged, and all the properties are empty strings, just like in the initialFormState.
If anyone needs more info I'd be happy to provide it. Thanks.
Adding a codesandbox link: https://codesandbox.io/s/admiring-haze-gsy59?file=/src/App.js
onChange on input does not emit the value, it emits an event.
Replace with onChange={e => setFormState({ ...formState, name: e.target.value })}

Automatically trim white spaces with Yup and Formik

I am using a Formik React Form and Yup validation defined on a schema:
export const Contact = yup.object<IContact>().shape({
contactName: yup
.string()
.trim('The contact name cannot include leading and trailing spaces')
.strict(true)
.min(1, 'The contact name needs to be at least 1 char')
.max(512, 'The contact name cannot exceed 512 char')
.required('The contact Name is required'),
});
Is there a way to have Yup trim white spaces without showing a message? So automatically trimming the spaces when a form is submitted?
Is there a way to have Yup trim white spaces without showing a message
Not in a single transform. The yup transform used by formik is only for validation.
You can create a seperate transform to use before passing the data, but its simpler to just valueToUse = userValue.trim() yourself.
You can do:
onSubmit={(values) => {
const castValues = Contact.cast(values)
})
reference:
https://github.com/jaredpalmer/formik/issues/473#issuecomment-499476056
I was able to achieve automatic removal of white spaces in an email field by overriding the onChange method from formik object. This is not the best solution to this but it works fine, especially where spaces are not allowed anywhere in the input field.
const { errors, touched, getFieldProps } = formik;
const { onChange } = getFieldProps('email');
const emailFieldProps = {
...getFieldProps('email'),
onChange: (e) => {
e.target.value = e.target.value.trim();
onChange(e);
},
};
return (
...
<TextField
{...emailFieldProps}
error={Boolean(touched.email && errors.email)}
helperText={touched.email && errors.email}
/>
...
)
You can also trim entered text on the go to completely limit user from using spaces at the end (example uses react native components):
const {handleSubmit, values, errors} =
useFormik({
validationSchema: EmailSchema(),
initialValues: {email: ''},
onSubmit: values => tryLogin(values.email)
})
...
<TextInput
value={values.email}
onChangeText={text => handleChange('email')(text.trim())}
error={errors.email}
/>
<Button title='SUBMIT' onPress={handleSubmit} />

formik + yup and validating fields that are in a child react component

lets say i have the following code:
let addressSchema = yup.object().shape({
firstname: yup.string().required().max(35),
lastname: yup.string().required().max(35),
company: yup.string().max(35),
address1: yup.string().required().max(35),
address2: yup.string().max(35),
city: yup.string().required(),
stateId: yup.string().required(),
zipcode: yup.string().required().length(5),
phone: yup.string().required().matches(phoneRegex, 'Phone number is not valid')
});
let checkoutFormSchema = yup.object().shape({
email: yup.string().email().required(),
billAddressAttributes: addressSchema,
shipAddressAttributes: addressSchema,
});
<Formik
initialValues={this.buildInitialValues()}
onSubmit={(values, actions) => {
}}
validationSchema={checkoutFormSchema}
>
{formikProps => (
<FieldWrapper
Label={<Label placement="left">Email address</Label>}
Input={<Field type="email" name="email" component={Input} />}
/>
<AddressFormFields prefix="billAddressAttributes" />
<AddressFormFields prefix="shipAddressAttributes" />
)}
</Formik>
where <AddressForm/> has a bunch of formik <Field/> components for the address, like how the email field is being made.
The email field works fine, triggering all events and properly showing the validation errors, but i cant get any of the formik <Field/> in the <AddressForm/> to trigger any events like touch, or show validation errors. I am guessing its because the formikProps isnt being passed down to the <AddressForm/>, but I can't figure out what to do. I've searched thoroughly through the documentation and stackoverflow but i couldn't find any examples of how to do this.
AddressForm should have the context as it's placed inside the Formik component. Perhaps, you've made some mistakes in manipulating fields' names and prefixes. Here is the working example of the nested form:
https://codesandbox.io/s/formik-nested-fields-1nvkj

Resources