I have a form that has a field items
, which stores an array of objects with the properties image
and name
. The image
property accepts a file but is optional, the name
field is required.
For some reason, when I touch the name field, the image field validation kicks in and it throws the error "Image is too large", which can be seen from formik's errors object. I don't understand why this is happening. Below is the code for the component and a codesandbox which you can view here https://codesandbox.io/s/new-fog-xs2wb?file=/src/components/form.js
import React from 'react';
import { Formik, Field, FieldArray } from 'formik';
import * as Yup from 'yup';
function MyForm(props) {
const FILE_SIZE = 5 * 1024 * 1024;
const SUPPORTED_FORMATS = ["image/jpg", "image/jpeg", "image/gif", "image/png"];
const validationSchema = Yup.object().shape({
items: Yup.array().of(Yup.object().shape({
image: Yup.mixed()
.test("fileSize", "Image is too large", (value) => value && value.size <= FILE_SIZE)
.test(
"fileFormat",
"Unsupported Format - We only allow images.",
(value) => value && SUPPORTED_FORMATS.includes(value.type)
),
name: Yup.string().required('Required')
}))
});
const initialValues = { items: [{
image: undefined,
name: ''
}]}
return (
<div className="container">
<Formik enableReinitialize={true}
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={async (values, { setSubmitting, resetForm }) => {
setSubmitting(true);
console.log(values);
setSubmitting(false);
}}>
{({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
isSubmitting,
setFieldValue,
}) => (
<form className="mt-3" onSubmit={handleSubmit}>
<FieldArray name="items">
{({ push, remove }) => (
<React.Fragment>
{values.items && values.items.length && values.items.map((item, index) => (
<div key={index}>
{/* <Field name={`items[${index}].image`} /> */}
<div className="form-group">
<label htmlFor="name">Name</label>
<input name={`items[${index}].name`} className="form-control" id="name" aria-describedby="nameHelp" onChange={handleChange} onBlur={handleBlur} />
<small id="nameHelp" className="form-text text-muted">Enter a descriptive name for the item.</small>
</div>
<button type="button" className="btn btn-danger mr-2 mb-2" onClick={() => remove(index)}>Remove</button>
</div>
))}
<button type="button" className="btn btn-secondary mr-2 mt-4" onClick={() => push({image: undefined, name: ''})}>Add</button>
<button type="submit" disabled={isSubmitting} className="btn btn-primary mt-4">Submit</button>
<pre className="mt-2">{JSON.stringify(errors, null, 2)}</pre>
</React.Fragment>
)}
</FieldArray>
</form>
)}
</Formik>
</div>)
}
export default MyForm;
How do I get this to work as desired? Your help is greatly appreciated.
The function that you used inside the test method should return false to show the resp error msg. Ref: https://github.com/jquense/yup#mixedtestoptions-object-schema
So you should do
!(value?.size > FILE_SIZE)
and!(value && !SUPPORTED_FORMATS.includes(value.type))
to make it work!Code updates: