Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

JD45's avatar
Level 7

Multiple Uploads with Inertia

Hello,

Thank you in advance for any help or pointing me in the right direction. I've Google'd this to death, but still haven't found a viable solution. I'm using Laravel as my backend with Inertia and Vue. I am also using PrimeVue for UI components.

The trouble I'm having is understanding how to handle multiple images with Inertia's form helper. As an example, I'm using this component which supports multiple uploads:

<FileUpload @input="form.images = $event.target.files[0]" v-model="form.images"
                                        :multiple="true"
                                        :showUploadButton="false"
                                        accept="image/*"
                                        :maxFileSize="3000000">
                                <template #empty>
                                    <p>Drag and drop files to here to upload.</p>
                                </template>
                            </FileUpload>

"images" is defined as an empty string and if I dd the request, I see only the first image in the array, not any additional images. I've tried setting images as an empty array but still only see the first image.

I'm not sure if I'm supposed to be looping over the images in my Vue components before submitting the form via post request?

Thank you once again for any help!

0 likes
7 replies
rodrigo.pedra's avatar

I'm not sure if I'm supposed to be looping over the images in my Vue components before submitting the form via post request?

Yes. You only get the first image because on the @input handler you are just saving the first image form.images = $event.target.files[0]

Also, why are you binding both to the @input event, and to v-model? You can bind to both, but making both mutate the same prop (form.images) can lead to unexpected results like the one you are getting.

Try one of these: (ONE, not both)

  • remove the @input handler and leave just the v-model
  • remove the v-model handler and change the @input handler to @input="form.images = event.target.files"

Inertia form helper should handle File objects automatically for you, per their docs:

When making visits that include files, Inertia will automatically convert the request data into a FormData object.

reference: https://inertiajs.com/forms#file-uploads

JD45's avatar
Level 7

@rodrigo.pedra Thank you for the reply.

Trying both of those suggestions gives me an empty array in the request filebag:

  +files: Symfony\Component\HttpFoundation\FileBag {#1819 ▼
    #parameters: []
  }

Whereas gets me at least a file:

<FileUpload @input="form.images = $event.target.files[0]"
                                        :multiple="true"
                                        :showUploadButton="false"
                                        accept="image/*"
                                        :maxFileSize="3000000">
                                <template #empty>
                                    <p>Drag and drop files to here to upload.</p>
                                </template>
                            </FileUpload>
  +files: Symfony\Component\HttpFoundation\FileBag {#1820 ▼
    #parameters: array:1 [▼
      "images" => Symfony\Component\HttpFoundation\File\UploadedFile {#35 ▼
        -test: false
        -originalName: "DSC_6510.JPG"
        -mimeType: "image/jpeg"
        -error: 0
rodrigo.pedra's avatar

@JD45 I am not familiar with the component you are using.

But if it forwards the original browser's input event the @input="form.images = $event.target.files" should have worked.

I tested in a small project with this vue component:

<template>
    <form @submit.prevent="send()">
        <input type="file" multiple @input="form.images = $event.target.files">
        <button type="submit">send</button>
    </form>
</template>

<script>
import {useForm} from '@inertiajs/inertia-vue3';

export default {
    data() {
        return {
            form: useForm({images: []}),
        };
    },

    methods: {
        send() {
            return this.form.post('/api/files');
        },
    },
};
</script>

And this route in ./routes/api.php

<?php

use Illuminate\Support\Facades\Route;
use Illuminate\Validation\ValidationException;

Route::post('/files', function () {
    throw ValidationException::withMessages([
        'images' => array_map(
            fn ($image) => $image->getClientOriginalName(),
            request()->file('images', [])
        ),
    ]);
});

And I got the images on the backend as expected. You can try with a plain <input type="file"> to verify.

I suggest you either look into the component's documentation or open an issue in their repository if the error persists.

1 like
fikurimax's avatar

I have the same case, but my problem is idk how to handle the validation errors. So the error goes like this

{
files.0: "error message 1",
files.1: "error message 2"
}
1 like
JD45's avatar
Level 7

@fikurimax, here is what I do:

<small v-if="form.errors.email" id="name-help"
                                   class="p-error">{{ form.errors.email }}</small>
NoLAstNamE's avatar

Using Inertia and PrimeVue FileUpload component.

For anyone who encountered the same issue, I have to change the way to select an image using the FileUpload component of PrimeVue.

Usually, we don't the url prop of the FileUpload component because the trigger of upload is in the submit button of our form.

Advanced FileUpload component drag-drop support from PrimeVue's example

<FileUpload name="demo[]" url="./upload.php" @upload="onAdvancedUpload($event)" :multiple="true" accept="image/*" :maxFileSize="1000000">
  <template #empty>
    <p>Drag and drop files to here to upload.</p>
  </template>
</FileUpload>

Modified to this

<FileUpload
  accept="image/*"
  :show-upload-button="false"
  :max-file-size="30000"
  @select="onSelect"
>
  <template #empty>
    <p>Drag and drop files to here to upload.</p>
  </template>
</FileUpload>

And the code for onSelect

const form = useForm({
  name: null,
  image: null,
});

const onSelect = (event) => {
  form.image= event.files[0];
};
anchan42's avatar

I had similar issues. This is what works for me. $event.files[0] would give you one file. You need the array of files to send over to the backend.

         <FileUpload @select="select" :multiple="true" :maxFileSize="1000000" />

Then in the script.


const form = useForm({
    avatar: null,
});
const select = ($event) => {
    form.avatar = $event.files;
};

Please or to participate in this conversation.