Laravel+Vue.js3+Inertiaでfilepondを使ったファイルアップロード項目がある編集画面に登録済みのファイルを表示できない

実現したいこと

Laravel + Vue.js 3 + Inertia で開発中のお知らせ機能に複数画像アップロードがあります。
登録済みの複数画像をお知らせ編集画面に表示出来ずに困っております。

前提

Laravel、Vue.js3、Inertia いずれも初心者です。

お知らせ投稿の項目は、
・タイトル
・ファイル(複数)
です。(項目は他にもありますが、ここでの質問には不要なので省略しています)

複数ファイルのアップロードに「filepond」ライブラリを使用することにしました。
また、Laravelで使いやすくなると思い、併せて「laravel-filepond」も使用することにしました。

DBは、newsテーブルとimagesテーブル、その中間テーブルがあります。

news --------- id title images --------- id filepath image_news --------- news_id image_id

発生している問題・エラーメッセージ

Create→Storeは成功したのですが、EditでFilepondを適用したInput[type=file]に登録済みの画像をセットすることが出来ずに困っています。

以下の画像のようなイメージです。
(各画像の右上「Upload complete」表示は不要で大丈夫です)
イメージ説明

該当のソースコード

文字数オーバーのため省略部分あります

Create.vue

javascript

1<script setup>2import { Head, useForm } from '@inertiajs/inertia-vue3';3import { onMounted, ref } from "vue";4import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';5import ValidationErrors from '@/Components/ValidationErrors.vue';6import vueFilePond, { setOptions } from 'vue-filepond';7import FilePondPluginFileValidateType from 'filepond-plugin-file-validate-type';8import FilePondPluginImagePreview from 'filepond-plugin-image-preview';9 10// Import filepond styles11import 'filepond/dist/filepond.min.css';12import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.min.css';13 14const props = defineProps({15 csrf_token: String16})17 18const filepondImagesInput = ref(null); // Reference the input to clear the files later19 20const form = useForm({21 title: null,22 images: [],23})24 25const storeNews = () => {26 form.transform((data) => {27 return {28 ...data,29 images: data.images.map(item => item.serverId) // Pluck only the serverIds30 }31 })32 form.post(route('news.store'), {33 forceFormData: true,34 onSuccess: () => {35 filepondImagesInput.value.removeFiles();36 }37 })38}39 40// Create FilePond component41const FilePond = vueFilePond(FilePondPluginFileValidateType, FilePondPluginImagePreview);42 43// Set global options on filepond init44const handleFilePondInit = () => {45 setOptions({46 credits: false,47 server: {48 url: '/filepond',49 headers: {50 'X-CSRF-TOKEN': props.csrf_token,51 }52 }53 });54};55 56// Set the server id from response57const handleFilePondImagesProcess = (error, file) => {58 form.images.push({id: file.id, serverId: file.serverId});59};60// Remove the server id on file remove61const handleFilePondImagesRemoveFile = (error, file) => {62 form.images = form.images.filter(item => item.id !== file.id);63}64</script>65 66<template>67 <Head title="新規登録" />68 69 <AuthenticatedLayout>70 <template #header>71 <h2 class="font-bold text-2xl text-stone-800 leading-tight">新規登録</h2>72 </template>73 74 <ValidationErrors></ValidationErrors>75 76 <section class="text-stone-800 body-font relative">77 <form @submit.prevent="storeNews" enctype="multipart/form-data">78 <div class="pt-10 pb-24">79 <div class="flex flex-wrap -m-2">80 <div class="p-2 w-full">81 <label for="title" class="form-label">タイトル<span class="badge-danger">必須</span></label>82 <input type="text" id="title" name="title" v-model="form.title" class="w-full form-ctrl">83 <p class="form-attention">100文字以内で入力してください</p>84 </div>85 <div class="p-2 w-full">86 <label class="block form-label">添付ファイル</label>87 <p class="form-attention">2MB以下のjpg/pngファイルを指定してください</p>88 <div>89 <FilePond90 name="images"91 ref="filepondImagesInput"92 class-name="my-pond"93 allow-multiple="true"94 accepted-file-types="image/jpeg, image/png"95 max-files="3"96 @init="handleFilePondInit"97 @processfile="handleFilePondImagesProcess"98 @removefile="handleFilePondImagesRemoveFile"99 />100 </div>101 </div>102 <div class="px-2 pt-10 w-full">103 <button class="btn-primary">登録</button>104 </div>105 </div>106 </div>107 </form>108 </section>109 110 </AuthenticatedLayout>111</template>

Edit.vue

javascript

1<script setup>2// importはCreateと同じため省略3 4const props = defineProps({5 news: Object,6 images: Array,7 csrf_token: String8})9 10const filepondImagesInput = ref(null); // Reference the input to clear the files later11 12const form = useForm({13 _method: 'PUT',14 id: props.news.id,15 title: props.news.title,16 images: props.images,17})18 19onMounted(() => {20 form.images.push(props.images); // ←試しにやってみましたが上手くいかず21})22 23const updateNews = id => {24 form.transform((data) => {25 return {26 ...data,27 images: data.images.map(item => item.serverId) // Pluck only the serverIds28 }29 })30 form.post(route('news.update', { news: id }), {31 forceFormData: true,32 onSuccess: () => {33 filepondImagesInput.value.removeFiles();34 }35 })36}37 38// Create FilePond component39// Createの40行目〜63行目まで同じため省略40</script>41 42<template>43 Createと同じ44</template>

NewsController.php

php

1<?php2 3namespace App\Http\Controllers;4 5use App\Http\Requests\StoreNewsRequest;6use App\Http\Requests\UpdateNewsRequest;7use App\Models\News;8use App\Models\Image;9use Illuminate\Support\Facades\Auth;10use Illuminate\Support\Facades\DB;11use Illuminate\Support\Facades\Storage;12use Inertia\Inertia;13use RahulHaque\Filepond\Facades\Filepond;14 15class NewsController extends Controller16{17 public function index()18 {19 // 省略20 }21 22 public function create()23 {24 return Inertia::render('News/Create');25 }26 27 public function store(StoreNewsRequest $request)28 {29 DB::beginTransaction();30 31 try {32 // 添付ファイル33 $news_images = Filepond::field($request->images)->getFile();34 $image_ids = array();35 if ( isset($news_images) ) {36 foreach ( $news_images as $n_img ) {37 $filepath = $n_img->store('news', 'public');38 $img = Image::create([39 'title' => $n_img->getClientOriginalName(),40 'filepath' => $filepath,41 ]);42 $image_ids[] = $img->id;43 }44 }45 46 $news = News::create([47 'title' => $request->title,48 ]);49 50 $news->images()->sync($image_ids);51 52 DB::commit();53 54 return to_route('news.index')->with([55 'message' => '登録しました。',56 'status' => 'success'57 ]);58 59 } catch (\Exception $e) {60 DB::rollBack();61 }62 }63 64 public function show(News $news)65 {66 // 省略67 }68 69 public function edit(News $news)70 {71 $images = Image::select('id', 'filepath')->orderBy('id')->get();72 73 return Inertia::render('News/Edit', [74 'news' => $news,75 'images' => $images,76 ]);77 }78 79 public function update(UpdateNewsRequest $request, News $news)80 {81 DB::beginTransaction();82 try {83 $news_images = Filepond::field($request->images)->getFile();84 $image_ids = array();85 if ( isset($news_images) ) {86 foreach ( $news_images as $n_img ) {87 $filepath = $n_img->store('news', 'public');88 $img = Image::create([89 'title' => $n_img->getClientOriginalName(),90 'filepath' => $filepath,91 ]);92 $image_ids[] = $img->id;93 }94 }95 96 $news->title = $request->title;97 $news->save();98 99 $news->images()->sync($image_ids);100 101 DB::commit();102 103 return to_route('news.index')->with([104 'message' => '更新しました。',105 'status' => 'success'106 ]);107 108 } catch (\Exception $e) {109 DB::rollBack();110 }111 }112 113 public function destroy(News $news)114 {115 //116 }117}

試したこと

英語はさっぱりですが、藁にもすがる気持ちで以下のYouTubeをみました。
Laravel Inertia Vue.js - Multiple image upload with FilePond.js
私がやりたいことは、実現は出来るだろうと思いましたが、この動画ではlaravel-filepondが使用されていないのでアプローチが違うと思いました。
laravel-filepondの使用をあきらめた方が早いのでしょうか???

補足情報(FW/ツールのバージョンなど)

Laravel 9
Vue.js 3
Inertia
filepond
laravel-filepond

コメントを投稿

0 コメント