I would like to validate if a file has been chosen using v-file-input and ValidationProvider from vee-validate.
Below is my code:
<v-flex>
<ValidationProvider rules="required" v-slot="{ errors }">
<v-file-input
show-size
accept=".xlsx"
placeholder="Click here to select your file"
label="File name"
:error="errors.length > 0"
:error-messages="errors[0]"
@change="selectFile"
>
</v-file-input>
</ValidationProvider>
</v-flex>
Somehow the validation works but it works too well even after I have chosen a file:
I am not sure what I have done wrong?
This was due to the fact that the v-file-input component actually returns an array of File objects in vue 3 (i.e., File[]), not a single File even though it's a single file upload and you kept multiple="false". Thus, the validation rules were not being applied correctly. Thats why, the validation was often failing because v was undefined.
To resolve this, I needed to update the validation rules to accept an array of File objects (File[] | undefined). Here’s how I revised the code:
<template>
<v-file-input v-model="internalValue" :rules="rules" />
</template>
<script setup lang="ts">
const rules = [
(v: File[] | undefined) => {
return (v && v.length > 0) || messages.validation.imagePath.required
},
(v: File[] | undefined) => {
console.log(v, 'val') // if you print this you can see you get an array
if (!v || v.length === 0) return true
const oversizedFile = v.find((file) => file.size > 5 * 1024 * 1024)
return !oversizedFile || messages.validation.imagePath.maxSize
},
(v: File[] | undefined) => {
if (!v || v.length === 0) return true
const invalidTypeFile = v.find((file) => !['image/jpeg', 'image/jpg'].includes(file.type))
return !invalidTypeFile || messages.validation.imagePath.invalidFormat
}
]
</script>
this solved the issue for me and it's convenient because you don't have to set validation errors manually