Fitur Upload Progress Bar Idikator Vue Laravel

Fitur Upload Progress Bar Idikator Vue Laravel

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

vue laravel form progress bar

Dan setelah upload berjalan maka progress bar pun berubah warna dengan tampilan seperti berikut

vue laravel progress bar

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.

Category:
Share:

Comments