example
File Upload
If you want to append data also during precognitive validation request you could either:
- set the corresponding option (validateFiles) in the UseFormOptions
- call the form function form.validateFiles()
Example
here a snapshot of code that can:
- perfom clientSide validation.
- skip sending file during precognitive validation
- Use base nuxt $fetch to make http request to backend
/**
* Post schema. Defined using Zod.
* Add specific file validations because it is
* sent during precognitive validation request. *
*/
const postSchema = z.object({
title: z.string().min(5).max(100),
content: z.string().min(10).max(1000),
friends: z.array(z.string()),
image: z.instanceof(File)
.refine(file => file.size <= 10 * 1024 * 1024, {
message: 'File size must be less than 10MB',
})
.refine(file => ['image/jpeg', 'image/png', 'image/gif'].includes(file.type), {
message: 'File must be JPEG, PNG, or GIF',
})
.refine(file => file.name.length > 0, {
message: 'File must have a name',
})
.refine(file => !!file.name.match(/^[a-z0-9]+\.[a-z0-9]+$/i), {
message: 'File name must be alphanumeric with an extension. No spaces or special characters.',
})
.nullable(),
})
type Post = z.infer<typeof postSchema>
/**
* Use the global $api to make backend request (to Laravel for example) defined in Nuxt Plugin.
* It includes already Zod parser for validation errors.
*/
const { $api } = useNuxtApp()
/**
* Define the form using useForm composable.
* The second argument is a function to submit the form data to the backend. Being complete agnostic,
* the headers to submit form data must be specified. Precognnitive header are already present.
* Here we use FormData to handle file upload.
* Client-side validation is specified in the UseFormOptions.
*/
const postForm = useForm(
(): Post => ({ title: '', content: '', friends: [], image: null }),
(data, headers) => {
const formData = new FormData()
formData.append('title', data.title)
formData.append('content', data.content)
data.friends.forEach((friend, index) => {
formData.append(`friends[${index}]`, friend)
})
if (data.image) {
formData.append('image', data.image)
}
headers.set('Content-Type', 'multipart/form-data')
return $api(
'/api/posts',
{
method: 'POST',
headers,
body: formData,
}
)
},
{
clientValidation: postSchema.parse,
validateFiles: true,
},
)
function addImage(e: Event) {
postForm.image = null
postForm.forgetErrors('image')
const input = e.target as HTMLInputElement
if (input.files && input.files[0]) {
postForm.image = input.files[0]
postForm.validate('image')
}
}
function handleSubmit() {
postForm.submit({
onBefore() {
postForm.forgetErrors()
return true
},
onStart: (data) => {
postSchema.parse(data)
}
})
}