Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to validate formik & Yup validation with file type and size ? #926

Closed
saurabh147sharma opened this issue Sep 20, 2018 · 22 comments
Closed

Comments

@saurabh147sharma
Copy link

Hi

I couldn't find any doc for file upload validation in formik and yup. Please help me how to do that ?

@jaredpalmer
Copy link
Owner

Yup doesn’t handle this. You can use your own validation function at either the form or field-level.

@alecchisi
Copy link

alecchisi commented Oct 18, 2018

After following this tutorial to integrate a file upload component in my form
https://hackernoon.com/formik-handling-files-and-recaptcha-209cbeae10bc
I've been able to test file size and type like this:
iconFile: Yup.mixed() .test('fileSize', "File Size is too large", value => value.size <= FILE_SIZE) .test('fileType', "Unsupported File Format", value => SUPPORTED_FORMATS.includes(value.type) )

where FILE_SIZE is a numeric constant and SUPPORTED_FORMATS is an array of valid image type strings ['image/jpg', 'image/jpeg', 'image/gif', 'image/png']

@alecchisi
Copy link

Try this:
https://codesandbox.io/s/4wrrx8qok0

@mfliri
Copy link

mfliri commented Jun 4, 2019

@alecchisi When I do

        yup.object().shape({
        file: yup.mixed().required('A file is required')
        .test('fileFormat', 'PDF only', (value) => {
          console.log(value); return value && ['application/pdf'].includes(value.type);
        }),

In my console only appears C:\fakepath\Filename.pdf not the file itself. My rendered input is

<input
    id="file"
    name="file"
    type="file"
    onChange={handleChange}
    className={
         errors.password && touched.password
         ? 'form-control is-invalid'
         : 'form-control'
     }
/>

What could be possibly wrong?

@alecchisi
Copy link

That is correct, because the html5 input tag like that only contains the filename (it is considered a text input). You should code a component like the one in my sandbox (or in the tutorial I've linked upper in this thread), and use the formik component to embed and expose correctly the corresponding object.

@mfliri
Copy link

mfliri commented Jun 4, 2019

@alecchisi Ahh, cool. Thanks!

@gaurav-pantelwar
Copy link

@alecchisi What if I want file to be an optional and also if any file selected validate file size and file type?

@ZephSibley
Copy link

ZephSibley commented Oct 21, 2019

I refactored alecchisi's example into something more simple and functional https://codesandbox.io/s/keen-morning-otxz6

@mariselvanm
Copy link

@ZephSibley While updating the Formik and Yup libraries in your code sandbox it just stopped working. Can you please look at it? Because I wasted a lot of time on this. So, if you update this it'll help people who are looking for the same kind of solution.

@monsieur-z
Copy link

Hi, I'm running into the same issue as @mariselvanm, I believe. I've isolated it in a sandbox.

With version 1.5.8 of Formik, I'm able to see the file size in the console when I select a picture: https://codesandbox.io/s/yup-formik158-86xny

In this sandbox, I've just updated the version of Formik to 2.0.3, and I've got undefined instead of the file size: https://codesandbox.io/s/yup-formik203-14vlq

@mariselvanm
Copy link

@jaredpalmer Is there any way we can validate using validate and validateScheme in a single form?

@jaredpalmer
Copy link
Owner

jaredpalmer commented Nov 14, 2019

@mariselvanm yes you can use both. I would not suggest it though. The results will be deeply merged.

@dorklord23
Copy link

dorklord23 commented Apr 21, 2020

After following this tutorial to integrate a file upload component in my form
https://hackernoon.com/formik-handling-files-and-recaptcha-209cbeae10bc
I've been able to test file size and type like this:
iconFile: Yup.mixed() .test('fileSize', "File Size is too large", value => value.size <= FILE_SIZE) .test('fileType', "Unsupported File Format", value => SUPPORTED_FORMATS.includes(value.type) )

where FILE_SIZE is a numeric constant and SUPPORTED_FORMATS is an array of valid image type strings ['image/jpg', 'image/jpeg', 'image/gif', 'image/png']

@alecchisi I follow your example but variable value in the callback is null :/

PS:
I have fixed this by added validation for value like @ZephSibley's code:

value && typeof value.arrayBuffer === 'function'

@alex-r89
Copy link

Hi there,

Sorry to comment on a closed issue but I think this may be useful to some people:

The solution posted by @alecchisi works very well for file uploads IF the field is required, however this will not work if the field is not required - for example if a file upload is optional for the user.

In this case, the solution will fail because the default value for the file (null in my case) will not pass on either value => value.size <= FILE_SIZE or value => SUPPORTED_FORMATS.includes(value.type).

In order to fix this for non required file uploads, I have the following yup scheme:

const validationSchema = object().shape({
  file: mixed()
    .test('fileSize', 'File too large', (value) => value === null || (value && value.size <= FILE_SIZE))
    .test(
      'fileFormat',
      'Unsupported file type',
      (value) => value === null || (value && SUPPORTED_FORMATS.includes(value.type))
    )
})


  const formik = useFormik({
    initialValues: {
      file: null
      // More values here
    },
// More code here

Just to also note, substituting this for mixed().nullable(true) will not work because it will still fail on the tests.

@caiosamarone
Copy link

@alex-r89 what if i want to check the height and the width of the image? Do you know how can I do this?

@sven5
Copy link

sven5 commented May 14, 2021

what about with multiple files?

@mihailsitnic
Copy link

mihailsitnic commented Jul 1, 2021

Use validation in a separate file:

const { errors } = props

function isEmpty(obj) {
return Object.keys(obj).length === 0
}

const isValid = isEmpty(errors)

@thinkDigitalZw
Copy link

thinkDigitalZw commented Jul 16, 2021

This is 2021, so I have assumptions something changed about that as the current implementation.

The code below when I console log the value object it returns VALUE C:\fakepath\ADVERT-PROCUREMENT-MANAGER-GMB.pdf

If I console log value?.size <= FILE_SIZE it returns false, hence rendering the error "File too large" in formik schema.

.test( "fileSize", "File too large", (value) => value && value.size <= FILE_SIZE )

What I want to achieve is simple.

  1. Get the actual numeric file size
  2. Know how to interpret the FILE_SIZE numeric e.g value of 1MB, 1GB etc

@SinaBYR
Copy link

SinaBYR commented Aug 17, 2021

After following this tutorial to integrate a file upload component in my form
https://hackernoon.com/formik-handling-files-and-recaptcha-209cbeae10bc
I've been able to test file size and type like this:
iconFile: Yup.mixed() .test('fileSize', "File Size is too large", value => value.size <= FILE_SIZE) .test('fileType', "Unsupported File Format", value => SUPPORTED_FORMATS.includes(value.type) )

where FILE_SIZE is a numeric constant and SUPPORTED_FORMATS is an array of valid image type strings ['image/jpg', 'image/jpeg', 'image/gif', 'image/png']

I was facing the same problem. Thank you!

@quyle92
Copy link

quyle92 commented Jul 28, 2022

For anyone received "C:\fakepath\Filename.pdf" as value in yup validation function, it is because yup was taking e.target.value as param in test validator. So in order to retrieve the whole file object at test validator, you need to set field value explicitly at native onChange event.
Therefore, instead of passing onChange={handleChange}, do this:

<input
    type="file"
    ...
    onChange={(e) => {
           form.setFieldValue(field.name, e.target.files[0]); 
    }}
    
/>

Note: Apart from handleChange, setFieldValue() also trigger validation. Ref: https://formik.org/docs/guides/validation#when-does-validation-run

@Khaan25
Copy link

Khaan25 commented Apr 30, 2023

.test('fileFormat', 'PDF only', (value) => {
          console.log(value); return value && ['application/pdf'].includes(value.type);
        })

Replace line with following: value.type.includes('application/pdf');

@carmel26
Copy link

The subject must be even close but the solution which i found was that simple
First you declare setFieldValue in your declarations
`const {
values,
errors,
touched,
isSubmitting,
setFieldValue,
handleBlur,
handleChange,
handleSubmit
} = useFormik({

  initialValues: {   
    evidence_for_accreditation_at_national_level : "",  
  },

  validationSchema : ApplicationSchemasValidation,
  onSubmit,
});

`
Here ApplicationSchemasValidation it is a Schemas which i declared in another file for my validations
And in your input just add it and remove handleChange event in onchange function

<input className={
${errors.evidence_for_accreditation_at_national_level && touched.evidence_for_accreditation_at_national_level ? "input-error" : ""}} id="evidence_for_accreditation_at_national_level" type="file" accept="application/pdf" onChange={(event) => { setFieldValue("evidence_for_accreditation_at_national_level", event.currentTarget.files[0]); }} onBlur={handleBlur} /> {errors.evidence_for_accreditation_at_national_level && touched.evidence_for_accreditation_at_national_level ? <p className="text-red-500 text-xs italic">{errors.evidence_for_accreditation_at_national_level}</p> : ""}

Hope it will help someone

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests