laravelvue.jsputinertiajs

InertiaJS file upload doesn't work with PUT method


I have form to update a product with necessary data (name,description..etc), it includes an input of type file, on change it will call function handleImage, which will then store the uploaded file in form.image:

<script setup>
import { useForm } from "@inertiajs/vue3";
const props = defineProps({ product: Object, categories: Object });

const form = useForm("UpdateProduct", {
    name: props.product.name,
    description: props.product.description,
    bestSelling: props.product.bestSelling,
    image: null,
});

const updateProduct = () => {
    console.log(form); // {name:"product 1", ..., File: {name: 'example.png', lastModified: 1704637318465, ....}}
    form.put(route("products.update", props.product.id), {
        preserveScroll: true,
        },
    });
};

const handleImage = (e) => {
    form.image = e.target.files[0];
    console.log(form.image); // File {name: 'example.png', lastModified: 1704637318465, ....}

};
</script>

<template>
    <form @submit.prevent="updateProduct">
        <div class="field">
            <label for="name">
                {{ $t("createProduct.name") }}
            </label>
            <input
                type="text"
                id="name"
                v-model.trim="form.name"
            />
            <div v-show="form.errors.name">
                <p class="text-danger text-center">
                    {{ form.errors.name }}
                </p>
            </div>
        </div>

        <div class="field">
            <label for="description">
                {{ $t("createProduct.description") }}
            </label>

            <textarea
                id="description"
                v-model.trim="form.description"
                required
                rows="5"
            >
            </textarea>
            <div v-show="form.errors.description">
                <p>
                    {{ form.errors.description }}
                </p>
            </div>
        </div>


        <div class="field">
            <label for="bestSelling">{{
                $t("createProduct.bestSelling")
            }}</label>
            <select
                id="bestSelling"
                required
                @click="selectOptions"
            >
                <option :selected="form.bestSelling === 1">Yes</option>
                <option :selected="form.bestSelling === 0">No</option>
            </select>
            <div v-show="form.errors.bestSelling">
                <p>
                    {{ form.errors.bestSelling }}
                </p>
            </div>
        </div>

        <div class="field">
            <input
                type="file"
                @input="handleImage"
                accept="image/png, image/gif, image/jpeg, image/bmp"
            />
            <progress
                v-if="form.progress"
                :value="form.progress.percentage"
                max="100"
            >
                {{ form.progress.percentage }}%
            </progress>
            <div v-show="form.errors.image">
                <p class="text-danger text-center">
                    {{ form.errors.image }}
                </p>
            </div>
        </div>

        <button
            class="btn btn-danger mx-2 w-25"
            @click="closeModal"
        >
            {{ $t("createProduct.cancel") }}
        </button>

        <button
            :class="{ 'opacity-25': form.processing }"
            :disabled="form.processing"
            type="submit"
            class="btn btn-secondary text-white w-25"
        >
            {{ $t("products.update") }}
        </button>
    </form>
</template>

    public function update(Request $request, Product $product)
    {
      dd($request->all());       
    }

In controller method update, if i send request payload without an uploaded image, it will recieve request:

array:8 [▼ // app\Http\Controllers\ProductController.php:96
  "name" => "product 1"
  "description" => "product description"
  "bestSelling" => false
  "category" => "Extra care"
  "image" => null
]

But if i upload an image, the result of dd($request->all()); will be an empty array, meaning no request payload recieved:

[] // app\Http\Controllers\ProductController.php:96

Solution

  • From the Inertia.js documentation:

    Multipart limitations

    Uploading files using a multipart/form-data request is not natively supported in some server-side frameworks when using the PUT,PATCH, or DELETE HTTP methods. The simplest workaround for this limitation is to simply upload files using a POST request instead.

    https://inertiajs.com/file-uploads