'Validating file presence with YUP
I'm using Yup to validate my form. In one of my form, I want to validate that one <input type="file" />
has a file.
I've tested this (and it's not working):
Yup.object().shape({
file: Yup.object().shape({
name: Yup.string().required()
}).required('File required')
I've the following error message in the console:
file must be a
object
type, but the final value was:null
(cast from the value{}
). If "null" is intended as an empty value be sure to mark the schema as.nullable()
Any idea?
Solution 1:[1]
Here is how I did it
import { object, string, mixed } from "yup"
const schema = object().shape({
attachment: mixed().test("fileSize", "The file is too large", (value) => {
if (!value.length) return true // attachment is optional
return value[0].size <= 2000000
}),
})
Solution 2:[2]
I solved it like this:
const schema = Yup.object().shape({
file: Yup.mixed().required('File is required'),
})
It throws an error if you attempt to submit the form without a file, and the error goes away when you have a file.
Solution 3:[3]
I know this is an old question, but I came across this same issue and tracked down what was happening.
When the validator runs, it's testing that the field type matches first. In this case, it checks to see if it's an object. Since it's not and the field is not marked as nullable
, it fails the validation with a type error. Yup never gets to the point of running required()
as it bails early.
So how do we adjust the message displayed when the type doesn't match and you don't want to use the nullable()
method? I looked at the source and discovered that the message is generated here. So it's part of the locale object. Thus, we can resolve it like this.
import * as Yup from 'yup';
import { setLocale } from 'yup';
setLocale({
mixed: {
notType: '${path} is required',
}
})
Yup.object().shape({
file: Yup.object().shape({
name: Yup.string().required()
}).label('File')
Now when the type is incorrect, your new message will display. The label()
method allows you to set a nice display name for the field as the message will be used in any invalid type situations in the validators.
Another alternative is to write a custom validator specifically for this field, but that seems like overkill in this scenario.
Solution 4:[4]
The other answers definitely get it right. This is an alternative approach that I've grown accustomed to following.
const validationSchema = Yup.object().shape({
[Form.File]: Yup.mixed()
.test({
message: 'Please provide a supported file type',
test: (file, context) => {
const isValid = ['png', 'pdf'].includes(getExtension(file?.name));
if (!isValid) context?.createError();
return isValid;
}
})
.test({
message: `File too big, can't exceed ${MAX_FILE_SIZE}`,
test: (file) => {
const isValid = file?.size < MAX_FILE_SIZE;
return isValid;
}
})
});
getExtension
is a custom utility to grab the ext type of a file. As Yup is usually utilized with Formik, the context argument will allow you to display an error message relevant to the test that you throw it in.
Using the useFormik
hook, you'll be able to grab the error from it:
const formik = useFormik({
validationSchema,
initialValues,
onSubmit
});
formik.errors[Form.File]
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | agm1984 |
Solution 3 | Dan |
Solution 4 | JaysQubeXon |