How to Upload Multiple Files via Ajax VueJs and Laravel 5.5

How to Upload Multiple Files via Ajax VueJs and Laravel 5.5

  • 2018-05-07 04:54 PM
  • 2115

When I first started using VueJs, it was a nightmare to find a decent tutorial on how to upload a single file using Ajax, let alone a tutorial explaining how to manage multiple files.

I have been dealing a couple of years with file management, mostly using VueJs and Laravel, so I thought writing a tutorial like this could help a lot of developers implement one of the coolest things in applications, which is real-time asset management.

First off, you will find many solutions online that are good but those who are early beginners will definitely struggle.

What I will cover here is writing your frontend and backend code that will allow you to upload multiple files. Additionally, I will give you a few tricks on how to apply this stuff to different situations.

This article will introduce a basic ability to pass multiple files from the UI to your backend. Once you have passed the attachments, they will automatically become UploadedFile object in PHP which are described in Laravel documentation.

<template>
    <div>
        <div class="form-group col-md-12">
            <label for="logo" class="control-label">Attachments</label>
            <br><br>
             <div class="col-md-12">
                <input type="file" multiple="multiple" id="attachments" @change="uploadFieldChange">
                <hr>
                <div class="col-md-12">
                    <div class="attachment-holder animated fadeIn" v-cloak v-for="(attachment, index) in attachments"> 
                        <span class="label label-primary">{{ attachment.name + ' (' + Number((attachment.size / 1024 / 1024).toFixed(1)) + 'MB)'}}</span> 
                        <span class="" style="background: red; cursor: pointer;" @click="removeAttachment(attachment)"><button class="btn btn-xs btn-danger">Remove</button></span>
                    </div>
                </div>
             </div>
             <br><br>
             <button class="btn btn-primary" @click="submit">Upload</button>
        </div>
    </div>
</template>
<script>
    export default {
        props: [
            'settings'
        ],
        data() {
            return {
                // You can store all your files here
                attachments: [],
                // Each file will need to be sent as FormData element
                data: new FormData(),
                errors: {
                },
                percentCompleted: 0, // You can store upload progress 0-100 in value, and show it on the screen
            }
        },
        watch: {
        },
        computed: {
        },
        methods: {
            getAttachmentSize() {
                
                this.upload_size = 0; // Reset to beginningƒ
                this.attachments.map((item) => { this.upload_size += parseInt(item.size); });
                
                this.upload_size = Number((this.upload_size).toFixed(1));
                this.$forceUpdate();
            },
            prepareFields() {
                
                if (this.attachments.length > 0) {
                    for (var i = 0; i < this.attachments.length; i++) {
                        let attachment = this.attachments[i];
                        this.data.append('attachments[]', attachment);
                    }
                }
            },
            removeAttachment(attachment) {
                
                this.attachments.splice(this.attachments.indexOf(attachment), 1);
                
                this.getAttachmentSize();
            },
            // This function will be called every time you add a file
            uploadFieldChange(e) {
                var files = e.target.files || e.dataTransfer.files;
                if (!files.length)
                    return;
                for (var i = files.length - 1; i >= 0; i--) {
                    this.attachments.push(files[i]);
                }
                // Reset the form to avoid copying these files multiple times into this.attachments
                document.getElementById("attachments").value = [];
            },
            submit() {
                this.prepareFields();
                var config = {
                    headers: { 'Content-Type': 'multipart/form-data' } ,
                    onUploadProgress: function(progressEvent) {
                        this.percentCompleted = Math.round( (progressEvent.loaded * 100) / progressEvent.total );
                        this.$forceUpdate();
                    }.bind(this)
                };
                // Make HTTP request to store announcement
                axios.post(this.settings.file_management.upload_files, this.data, config)
                .then(function (response) {
                    console.log(response);
                    if (response.data.success) {
                        console.log('Successfull Upload');
                        toastr.success('Files Uploaded!', 'Success');
                        this.resetData();
                    } else {
                        console.log('Unsuccessful Upload');
                        this.errors = response.data.errors;
                    }
                }.bind(this)) // Make sure we bind Vue Component object to this funtion so we get a handle of it in order to call its other methods
                .catch(function (error) {
                    console.log(error);
                });
            },
            // We want to clear the FormData object on every upload so we can re-calculate new files again.
            // Keep in mind that we can delete files as well so in the future we will need to keep track of that as well
            resetData() {
                this.data = new FormData(); // Reset it completely
                this.attachments = [];
            },
            start() {
                console.log('Starting File Management Component');
            },
        },
        created() {
            this.start();
        }
    }
</script>

FileManagement.vue

You can check my complete Laravel project at https://github.com/asabanovic/file-management-vuejs

I have pushed my code to github.

Download it, run it, play with it.

If you have come up to this point of the article, please clap and comment if you would like to see new sequels of the article such as:

1. Properly storing files on disk and database

2. Building a data library (pulling already saved attachments before uploading new ones)

3. Ability to delete old and new attachments

4. Separating attachments among different users so you can only see your uploaded files

5. Setting up file size limitations per user

6. Limiting to specific file formats

7. Uploading and previewing images

8. And more …

Don’t forget to clone your Github https://github.com/asabanovic/file-management-vuejs !

Real Time Chat With Laravel Broadcast, Pusher and Vuejs
https://goo.gl/TwDcck

Horizontal Feed Component with Sass and VueJs 2
https://goo.gl/L4c7kD

Vue.js 2 Essentials: Build Your First Vue App
https://goo.gl/zn3ta8