Pendahuluan
Perkembangan sebuah proses yang sedang berlangsung ketika user berinteraksi dalam sebuah aplikasi menjadi sangat penting untuk mengetahui progress dari tindakannya. Dalam artikel sebelumnya, Membuat fitur bulk import Laravel Excel 3.1, teman-teman Daengweb meminta bagaimana jika proses upload tersebut memiliki progress bar untuk mengetahui perkembangannya. Untuk menjawab hal tersebut, maka saya akan menuliskannya dengan contoh kasus yang berbeda dan dalam artikel yang berbeda juga.
Mengapa demikian? Sebab fungsi upload dan progress bar indikator adalah dua fitur yang berbeda, sehingga teman teman yang ikut belajar lainnya dapat memahami satu persatu terlebih dahulu sebelum menyatukan keduanya #eh.
Baca Juga: Membuat Validasi Form Menggunakan Vuelidate
Membuat Form Upload
Case yang akan diangkat tetap dalam cakupan upload file yakni membuat fitur file manager, namun yang berbeda kali ini kita akan memanfaatkan Javascript, dalam hal ini Vue.js untuk meng-handle form upload yang akan dibuat. Install Laravel terlebih dahulu dengan command:
composer create-project --prefer-dist laravel/laravel progress-bar-laravel-vue
Kemudian masuk kedalam folder project yang baru saja dibuat dan jalankan command:
npm install
Dan kita akan menggunakan Axios untuk proses ajax request, install juga dengan command:
npm install axios
Buka file resources/views/welcome.blade.php
kemudian modifikasi menjadi:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Laravel Progress Bar</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
</head>
<body>
<div class="container" id="dw">
<form-upload />
</div>
<script src="{{ asset('js/app.js') }}"></script>
</body>
</html>
Terdapat custom component yang digunakan yakni tag <form-upload
, so, buat file resources/js/components/FormUpload.vue
kemudian tambahkan code berikut:
<template>
<div class="row" style="padding-top: 10px">
<div class="col-md-6">
<div class="card">
<div class="card-body">
<form action="javascript:void(0)" @submit.prevent="uploadSubmit"
enctype="multipart/form-data" method="post">
<div class="alert alert-success" v-if="message">{{ message[0] }}</div>
<div class="form-group">
<label for="">Upload file</label>
<input type="file" class="form-control" ref="file" name="file" @change="fileUpload($event.target)" required>
</div>
<div class="form-group">
<button class="btn btn-danger btn-sm"
:disabled="isLoading">{{ isLoading ? 'Loading...':'Upload' }}</button>
</div>
</form>
<div class="progress">
<!-- PROGRESS BAR DENGAN VALUE NYA KITA DAPATKAN DARI VARIABLE progressBar -->
<div class="progress-bar" role="progressbar"
:style="{width: progressBar + '%'}"
:aria-valuenow="progressBar"
aria-valuemin="0"
aria-valuemax="100"></div>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h3 class="card-title">List File</h3>
</div>
<div class="card-body">
<!-- BAGIAN INI AKAN MENAMPILKAN FILE YANG TELAH DIUPLOAD -->
<img v-for="(row, index) in files" :src="'storage/' + row" :key="index" alt="" width="150px" height="150px" class="img-fluid">
</div>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
progressBar: 0, //VARIABLE INI NILAINYA AKAN BERUBAH SESUAI PROGRESS UPLOADING
message: '',
isLoading: false,
file: '', //UNTUK MENYIMPAN DATA FILE YANG AKAN DIUPLOAD
files: [] //MENYIMPAN DATA FILE YANG TELAH DIUPLOAD
}
},
created() {
this.getAllFile()
},
methods: {
//MENGAMBIL DATA FILE YANG TELAH DI-UPLOAD
getAllFile() {
axios.get('/api/file')
.then((response) => {
this.files = response.data
})
},
//MENYIMPAN DATA FILE YANG AKAN DI-UPLOAD
fileUpload(event) {
this.file = event.files[0]
},
//MENGIRIM FILE UNTUK DI-UPLOAD
uploadSubmit() {
this.isLoading = true
this.message = ''
let formData = new FormData();
formData.append('file', this.file);
axios.post('/api/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
},
//FUNGSI INI YANG MEMILIKI PERAN UNTUK MENGUBAH SEBERAPA JAUH PROGRESS UPLOAD FILE BERJALAN
onUploadProgress: function( progressEvent ) {
//DATA TERSEBUT AKAN DI ASSIGN KE VARIABLE progressBar
this.progressBar = parseInt(Math.round((progressEvent.loaded * 100) / progressEvent.total))
}.bind(this)
})
.then((response) => {
setTimeout(() => {
this.message = response.data
this.isLoading = false
this.reset()
this.getAllFile()
})
})
},
//RESET FORM UPLOAD
reset() {
this.$refs.file.value = '';
}
}
}
</script>
Terakhir untuk Javascript-nya, modifikasi file resources/js/app.js
menjadi:
import Vue from 'vue'
import FormUpload from './components/FormUpload.vue'
new Vue({
el: '#dw',
components: {
FormUpload
}
})
Baca Juga: Upload & Resize Image di Laravel
Handle File Uploaded
Form upload file telah dibuat dengan menggunakan component Vue.js, dimana didalamnya terdapat dua buah end point yang digunakan untuk mengirim request ke server. Pada sub topik ini, tugas kita adalah membuat fungsi untuk meng-handle data yang dikirimkan. Buat controller dengan command:
php artisan make:controller UploadController
Buka file app\Http\Controllers\UploadController.php
, kemudian tambahkan method berikut untuk meng-handle file yang telah di-upload:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class UploadController extends Controller
{
public function uploadFile(Request $request)
{
$this->validate($request, [
'file' => 'required|mimes:jpg,png,jpeg'
]);
if ($request->hasFile('file')) {
$file = $request->file('file');
$filename = time() . '.' . $file->getClientOriginalExtension();
//MENYIMPAN FILE KE DALAM FOLDER PUBLIC (note: sesuai disk dari filesystem)
//DALAM HAL INI KE storage_path
$file->storeAs(
'public', $filename
);
return response()->json(['Upload Success']);
}
}
}
Masih dengan file yang sama, tambahkan method selanjutnya untuk mengambil list file yang ada didalam folder:
...
public function readFile()
{
$files = scandir(storage_path('app/public'));
$allFile = array_diff($files, ['.', '..', '.gitignore']);
return response()->json($allFile, 200);
}
...
Terakhir, buka file routes/api.php
kemudian tambahkan kedua route berikut:
Route::post('/upload', 'UploadController@uploadFile');
Route::get('/file', 'UploadController@readFile');
Tampilan dari aplikasi yang sedang dibuat sebelum melakukan upload file akan tampak seperti berikut
Dan setelah upload berjalan maka progress bar pun berubah warna dengan tampilan seperti berikut
Kesimpulan
Fitur ini adalah salah satu bagian dari UX untuk membantu user dalam mengetahui sejauh mana progress yang dilakukannya berlangsung. Artikel ini juga sekali lagi mengulang bagaimana melakukan interaksi antara Vue dan Laravel, sehingga teman-teman yang masih belajar persoalan ini, bisa membaca artikel yang terakait sehingga dapat mempercepat teman-teman dalam memahaminya dengan berbagai case.
Ohya untuk dokumentasi code dari artikel ini dapat kamu lihat di Github.
Comments