how to make asychronous multiple upload files with progress bar in laravel 5.

Updated: Jan 28, 2025

how to make asychronous multiple upload files with progress bar in laravel 5.

To make asynchronous multiple file uploads with a progress bar in Laravel 5, you can use a combination of Laravel's built-in file uploading features, JavaScript, and a popular JavaScript library like jQuery or Axios for handling asynchronous requests. Here's a step-by-step guide to help you achieve this:

  1. Set up your Laravel project and create a new controller for handling file uploads.
composer create laravel/laravel my-project
php artisan make:controller FileUploadController
  1. Create a new route for the file upload action. Update routes/web.php:
Route::post('/upload', 'FileUploadController@upload');
  1. Update the FileUploadController to handle the file uploads and return a JSON response.
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;

class FileUploadController extends Controller
{
    public function upload(Request $request)
    {
        if ($request->hasFile('files[]')) {
            $files = $request->file('files[]');
            $progress = [];

            foreach ($files as $file) {
                $name = $file->getClientOriginalName();
                $size = $file->getSize();
                $mimeType = $file->getMimeType();
                $path = Storage::putFile('public/uploads', $file);
                $progress[] = [
                    'name' => $name,
                    'size' => $size,
                    'status' => 'success',
                    'path' => $path,
                ];
                $file->storeAs('public/uploads', $name);
            }

            return response()->json($progress);
        }

        return response()->json(['error' => 'No files were uploaded.'], 400);
    }
}
  1. Create a new JavaScript file to handle the asynchronous file uploads and progress bar.
touch resources/js/file-upload.js
  1. Update the FileUploadController to return a view for the file upload form.
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;

class FileUploadController extends Controller
{
    public function upload(Request $request)
    {
        if ($request->hasFile('files[]')) {
            $files = $request->file('files[]');
            $progress = [];

            foreach ($files as $file) {
                $name = $file->getClientOriginalName();
                $size = $file->getSize();
                $mimeType = $file->getMimeType();
                $path = Storage::putFile('public/uploads', $file);
                $progress[] = [
                    'name' => $name,
                    'size' => $size,
                    'status' => 'uploading',
                ];
                $file->storeAs('public/uploads', $name);
            }

            return response()->json($progress);
        }

        return view('file-upload');
    }
}
  1. Create a new blade file for the file upload form.
touch resources/views/file-upload.blade.php

Update the file-upload.blade.php with the following code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>File Upload</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.21.1/axios.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <style>
        #progress-bar {
            width: 100%;
            height: 20px;
            background-color: #ddd;
            position: relative;
        }

        #progress {
            height: 100%;
            background-color: #4CAF50;
            position: absolute;
            top: 0;
            left: 0;
        }
    </style>
</head>
<body>
    <form action="{{ route('upload') }}" method="post" enctype="multipart/form-data" id="file-upload-form">
        @csrf
        <input type="file" name="files[]" multiple id="files">
        <button type="submit">Upload Files</button>
    </form>
    <div id="progress-bar">
        <div id="progress"></div>
    </div>

    <script>
        $('#file-upload-form').submit(function(e) {
            e.preventDefault();
            let files = $('#files')[0].files;
            let progress = [];
            let totalSize = 0;

            for (let i = 0; i < files.length; i++) {
                let file = files[i];
                let xhr = new XMLHttpRequest();
                xhr.open('POST', '{{ route('upload') }}', true);
                xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
                xhr.onreadystatechange = function() {
                    if (xhr.readyState === XMLHttpRequest.DONE) {
                        let response = JSON.parse(xhr.responseText);
                        let index = progress.findIndex(p => p.name === file.name);
                        if (index !== -1) {
                            progress[index].status = 'success';
                            updateProgress(progress, totalSize, index);
                        }
                    }
                };
                let formData = new FormData();
                formData.append('files[]', file);
                xhr.send(formData);
                totalSize += file.size;
                progress.push({
                    name: file.name,
                    size: file.size,
                    status: 'pending'
                });
            }
        });

        function updateProgress(progress, totalSize, index) {
            let percentage = Math.round((progress[index].size / totalSize) * 100);
            $('#progress')
                .css('width', percentage + '%')
                .text(percentage + '%');
            progress[index].percentage = percentage;
        }
    </script>
</body>
</html>
  1. Update the app/Providers/AppServiceProvider.php to register the JavaScript file.
namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Blade;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        if (! app()->isProduction()) {
            $this->registerBladeComponents();
        }

        Blade::component('file-upload', 'FileUpload');
    }

    protected function registerBladeComponents()
    {
        Blade::component('file-upload', 'App\Http\Components\FileUpload');
    }
}
  1. Create a new directory resources/js/components and create a new file FileUpload.php inside it.
mkdir resources/js/components
touch resources/js/components/FileUpload.php

Update the FileUpload.php with the following code:

namespace App\Http\Components;

use Illuminate\View\ComponentFactory;

class FileUpload
{
    public function render()
    {
        return view('file-upload');
    }
}
  1. Update the resources/js/app.js to import the FileUpload component.
import Vue from 'vue';
import App from './App.vue';
import FileUpload from './components/FileUpload';

Vue.component('file-upload', FileUpload);

new Vue({
    render: h => h(App),
}).$mount('#app');