<Field validate={(fieldValue) => ... } />
For now field level validaiton funciton gives us only field value.
<Field validate={(fieldValue, formikBag) => ... } />
I want to have access to formikBag inside of field level validation.
Pass additional argument with formikBag to validate callback function.
I want to have possibility to access other formik values to create dependent validation. E.g. I have Field1 and Field2. Field2 should be invalid if Field1 is true and Field2 have some values inside. Form is reused and you can compound it from smallest reuseable pieces. It means sometimes you can have Field2 defined or undefined, that is why I don't want to use for this case global Global Formik validation method - no, bcs of -> I want to see validation on component Blur, and want to compound form from smallest Fields element that can be included or not dynamically. Field Field nesting just to have form values inside of second Field validation No. Just have a look at this. Unnecessary component just to retrieve values I should have access to.Describe alternatives you've considered
<FIeld>
{
({form}) => <FIeld validate={value => form.values.FIELD1} > ...</Field>
}
</Field>
Having same issue here. We have range inputs, where numbers should not revert range (e.g. min value should not be more than max and vice versa). Lacking this feature forces us to do some complicated solutions like top level validation which is really hard to follow with a huge form. I believe you pass the whole form object as a second parameter into field validation function then I can decide whatever I want to use it for.
I agree. If the formik bag is available to a <Field>'s children, why would it not be available to validate as well?
This missing feature is causing a lot of issues for me as well, especially with related fields like password and re-enter password which need cross-validation. I would prefer to use field-level validation for this but it's impossible unless you can get access to up-to-date values. I tried to pass the current form object into my validation function but the values are one render cycle behind and therefore useless. Any update on making this possible?
We are also finding it troublesome for implementing cross field validation. It would be great, when using the useField-Hook, FieldMetaProps would not only include the value "plucked out from values", but also the values themselves. Like that, cross-field validation would be easy to implement.
I would also like support for something like this. Form level validation would work if I was able to tell if fields had been touched or not.
Seems reasonable, can this be done with useEffect though?
I am not sure why/where you would use useEffect. I thought it should be easy to not "pluck out from values" the one value of the respective field, but instead give all those values to the field, isn't it?
Yeah that鈥檚 fine by me
Great! Are you saying that you will be working on it?
I鈥檓 running into the same issue with range fields. In my case, validation props like min/max are strings that refer to other values in the formik values object. So my range inputs are just components that wrap formik inputs.
I managed to create a workaround by using
When the validation callback is called I iterate through each yup validator and provide it the values object.
I tried to use the useField validate prop, but there wasn鈥檛 any point because I had to pass in the formik values object. I got that from useFormikContext. This resulted in duplicated rendering and terrible performance.
I have this same issue. In my form I have a date field, and two other time fields in which their time must be after 'now', if the selected day is today. So I'm having trouble validating these time fields dynamically when the date is changed.
I tried something like @Menardi mentioned above, using the useField hook, and the useFormikContext to get the value of the date field, and use it inside the validate of the validate method. But the performance loss was huge, and for some reason I didn't got the data flow right, the validate method passed to the useField hook, appears to be being called before the updated date value, comes from the useFormiKContext hook :/
I successfully managed to get my validation to work with a little hack:
const { validateField, values } = useFormikContext();
const fieldValue1 = values?.fieldValue1;
const fieldValue2 = values?.fieldValue2;
const validate = useCallback(
value => {
// validation logic
},
[fieldValue1, fieldValue2]
);
...
const [field, meta, helpers] = useField({
name: fieldName,
validate
});
useEffect(() => {
const timeoutId = setTimeout(() => validateField(fieldName), 50);
return () => clearTimeout(timeoutId);
}, [fieldName, validate, validateField]);
By the time the validate method of invoked by formik, the other field's values weren't propagated yet to the component updating the validate method, but with this useEffect I re-invoke the validation of the field once, and it did the trick.
Is it a hack? Yes. Does it work? Yes.
I managed to reference other fields with custom validation using a ref. Full example below -- don't let the length of the example throw you off, it's a clean and simple solution.
Relevant code: const fieldRef = useRef();, <Field>{({ form, field }) => <input ref={ref} {...field} />}</Field>, <Field validation={val => myValidationFn(val)} /> and myValidationFn()
TLDR: Any extra field I want to reference in my validation is wrapped within <Field></Field> and has a ref added to the child input. Ref value is called in a custom validation function via the validate prop: <Field validate={val => customFn(val)} /> -- yup validations are preserved and ran along side your custom validation function.
import React, { useRef } from 'react';
import { Formik, Form, Field } from 'formik';
import MyFeedbackComponent from '/path/to/MyFeedbackComponent';
import * as yup from 'yup';
const MyComponent = props => {
const fieldRef = useRef();
const defaults = {
myReferenceField: null,
myOtherField: null,
};
const schema = yup.object().shape({
myReferenceField: yup.number().required('Reference field is required.'),
myOtherField: yup.number().required('My other field is required.'),
});
const handleSubmit = (values, resetForm, setSubmitting) => {
const { myReferenceField, myOtherField } = values;
// Your submit payload, API call, form/submit reset etc. here...
};
const myValidationFn = otherFieldVal => {
const limit = 100;
const referenceVal = fieldRef.current.value;
const errorMsg = `Total must be under ${limit}.`;
if (referenceVal) {
// Your custom condition and error.
const underLimit = otherFieldVal * referenceVal < limit;
return !underLimit && errorMsg;
}
return true;
};
return (
<Formik
initialValues={defaults}
enableReinitialize={true}
validationSchema={schema}
onSubmit={(values, {resetForm, setSubmitting}) => (
handleSubmit(values, resetForm, setSubmitting)
)}>
{form => {
return (
<Form>
<label>
/* This field is written this way so we can attach a ref to it.
* That way the most recent state value for this field is
* available in our custom validation function. */
<Field type="number" name="myReferenceField">
{({form, field}) => <input ref={fieldRef} {...field} />}
</Field>
<MyFeedbackComponent name="myReferenceField" />
</label>
<label>
// This field will call a custom validation function that will
// reference fieldRef's value.
<Field
type="number"
name="myOtherField"
validate={otherFieldVal => myValidationFn(otherFieldVal} />
<MyFeedbackComponent name="myOtherField" />
</label>
<button type="submit" disabled={form.isSubmitting}>
Submit
</button>
</Form>
)};
}
</Formik>
);
};
Any news on this?
I agree that the values should be passed as a second argument to the validate function. Here's a quick workaround in the meantime:
```js
const {
values,
validateField
}: FormikProps
useEffect(() => {
validateField("amount");
}, [values.amountType, validateField]);
```
It also works to provide the values to your validation function at the time of render, i.e have your validation function derived from a returned function:
export const validateLaunchDateIsBeforePreLaunch = ( values ) => {
return (launchDate) => {
const preLaunchDate = values.preLaunch;
const myIsBefore = (preLaunchDate && isBefore(new Date(launchDate), new Date(preLaunchDate)));
if(myIsBefore) {
return "Launch date is before pre launch date";
}
};
};
const { values } = useFormikContext();
return (
<Field
name="launchDate"
validate={validateLaunchDateisBeforePreLaunch(values)}
.../>
)}
Most helpful comment
Having same issue here. We have range inputs, where numbers should not revert range (e.g. min value should not be more than max and vice versa). Lacking this feature forces us to do some complicated solutions like top level validation which is really hard to follow with a huge form. I believe you pass the whole form object as a second parameter into field validation function then I can decide whatever I want to use it for.