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:
- 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
- Create a new route for the file upload action. Update
routes/web.php
:
Route::post('/upload', 'FileUploadController@upload');
- 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);
}
}
- Create a new JavaScript file to handle the asynchronous file uploads and progress bar.
touch resources/js/file-upload.js
- 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');
}
}
- 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>
- 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');
}
}
- Create a new directory
resources/js/components
and create a new fileFileUpload.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');
}
}
- Update the
resources/js/app.js
to import theFileUpload
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');