Sinnbeck's avatar
Level 102

Livewire - preview filenames before upload

I am just giving livewire a try for my next project but I am stuggling a bit with finding a solution for this.

I have page for uploading files.. Any file, so no image preview is needed. But I would like to show the file, and allow the user to delete it if they regret adding it. So multi-file upload with drag-and-drop or click to select.

I know I can use something like dropzone to do this, but the problem is that I don't want the files to be uploaded on drop. Instead I was hoping to somehow append the files to livewires upload request when the form is submitted.

Currently I am just using alpine to catch dropped files, and that works file. But I dont know what to do with them afterwards :)

             handleFileDrop(e) {
                    if (e.dataTransfer.files.length > 0) {
                        const files = e.dataTransfer.files;
                        this.files = this.files.concat(...files)
                    }
                },
                files: []
0 likes
8 replies
Sinnbeck's avatar
Level 102

I played around wtih letting livewire handle them (wire:model) and upload them to temp from my alpine call

const files = e.dataTransfer.files;
@this.uploadMultiple('files', files)

But both seem to replace the files, if the user tries to add more. Maybe there is a way to append instead of overwrite?

Snapey's avatar

I created this recently, copied and adapted from other scripts

              <div
                        class=""
                        x-data="drop_file_component()">
                        <div
                            class="flex flex-col items-center justify-center p-8 py-6 m-4 border border-dashed rounded-lg"
                            x-bind:class="dropingFile ? 'bg-slate-400 border-slate-500' : 'border-slate-500 bg-slate-200'"
                            x-on:drop="dropingFile = false"
                            x-on:drop.prevent="
                                handleFileDrop($event)
                            "
                            x-on:dragover.prevent="dropingFile = true"
                            x-on:dragleave.prevent="dropingFile = false">
                            <div wire:loading.remove class="flex flex-col items-center">
                                <svg xmlns="http://www.w3.org/2000/svg" class="w-16 h-16" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 13h6m-3-3v6m-9 1V7a2 2 0 012-2h6l2 2h6a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2z" />
                                </svg>
                                <div class="text-center" wire.target="files">Drop Your Files Here</div>
                            </div>
                            <div class="flex-col items-center mt-1 " wire:loading.flex wire.target="files">
                                <svg class="w-16 h-16 mr-3 -ml-1 text-slate-900 animate-spin" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
                                    <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
                                    <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
                                </svg>
                                <div>Processing Files</div>
                            </div>
                        </div>
				</div>

and

<script>
function drop_file_component() {
            return {
                dropingFile: false,
                handleFileDrop(e) {
                    if (e.dataTransfer.files.length > 50) {
                        alert("Only 50 files accepted at once.");
                        return;
                    }
                    if (event.dataTransfer.files.length > 0) {
                        const files = e.dataTransfer.files;
                        @this.uploadMultiple('files', files,
                            (uploadedFilename) => {}, () => {}, (event) => {}
                        )
                    }
                }
            };
        }
    </script>

don't know if it helps.

The livewire end stores the images as soon as the files attribute is updated, then I list the files back to the user and allow them to delete if not required

Sinnbeck's avatar
Level 102

@Snapey Yeah I have mostly the same, except I have added a hidden input (file) that is hooked up to a label, that allows click to select a file :)

<input type="file" multiple wire:model="files" id="file-upload" class="hidden">
<label class="flex flex-row justify-start items-center gap-2 p-5 cursor-pointer" for="file-upload"
                       x-on:drop="droppingFile = false"
                       x-on:drop.prevent="handleFileDrop($event)"
                       x-on:dragover.prevent="droppingFile = true"
                       x-on:dragleave.prevent="droppingFile = false">
                    <svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 text-aalund-500" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
                        <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z" />
                    </svg>
                    <div >
                        <h3 class="text-2xl">Upload files</h3>
                    </div>
                </label>
OussamaMater's avatar

@Sinnbeck I have read this one and "Facades are singletons", and all I can say, the quality is just insane, very well written and so informative, thanks for sharing these great articles!

2 likes
OussamaMater's avatar

@Sinnbeck I just was being honest, I loved both articles specially the one about facades, will definitely finish all of them.

2 likes

Please or to participate in this conversation.