Laravel Vue File Upload Example

Here are the steps to upload a file using Laravel and Vue.js.

Step 1: Install Laravel

composer create-project laravel/laravel vuefileupload --prefer-dist

After installation, go to the project folder root and type the following command.

npm install

It installs all the necessary dependencies to build Vue components.

Step 2: Configure the database.

Add your database credentials in the .env file.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=vueupload
DB_USERNAME=root
DB_PASSWORD=

Step 3: Create a model and migration files.

To create both files, insert the following command.

php artisan make:model FileUpload -m

It generates both model and migration files.

Step 4: Define the schema in the migration file.

Go to the create_file_uploads_table.php file and add the schema to it.

Schema::create('file_uploads', function (Blueprint $table) {
   $table->increments('id');
   $table->string('image_name');
   $table->timestamps();
});

Migrate the table into the database.

php artisan migrate

Step 5: Define the routes in the web.php file.

Define the following route in the web.php file.

Route::post('/image/store', 'ImageController@store');

Create an ImageController.php file via the following command.

php artisan make:controller ImageController

In that file, define the store function.

<?php

namespace App\Http\Controllers;
use App\FileUpload;

use Illuminate\Http\Request;

class ImageController extends Controller
{
    public function store(Request $request)
    {

    }
}

Step 6: Create a Vue component to upload a file.

Go to the resources  >>  assets  >>  js  >>  components  folder and create a new file called ImageuploadComponent.vue.

// ImageuploadComponent.vue

<template>
    <div class="container" id="app">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card card-default">
                    <div class="card-header">File Upload Component</div>
                    <div class="card-body">
                        We need to write here file upload HTML code.
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        
    }
</script>

We have created a new component. The next step is to register that component into the resources  >>  assets  >>  js  >>  app.js file.

// app.js


/**
 * First we will load all of this project's JavaScript dependencies which
 * includes Vue and other libraries. It is a great starting point when
 * building robust, powerful web applications using Vue and Laravel.
 */

require('./bootstrap');

window.Vue = require('vue');

/**
 * Next, we will create a fresh Vue application instance and attach it to
 * the page. Then, you may begin adding components to this application
 * or customize the JavaScript scaffolding to fit your unique needs.
 */

Vue.component('image-component', require('./components/ImageuploadComponent.vue'));

const app = new Vue({
    el: '#app'
});

e removed the example component from this file because we no longer need that.

Step 7: Compile the app.js file code.

We created the component, but the changes are still not reflected in the public>>  js  >>  app.js file. So we need to recompile our code. Go to the CMD and hit the following command.

npm run dev

It generates an app.js file in the public>>  js folder. Now, include this component in the welcome.blade.php file.

<!doctype html>
<html lang="{{ app()->getLocale() }}">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>File Upload Tutorial</title>
        <link href="https://fonts.googleapis.com/css?family=Raleway:100,600" rel="stylesheet" type="text/css">
        <link href="{{ asset('css/app.css') }}" rel="stylesheet"/>
    </head>
    <body>
        <div class="container" id="app">
            <image-component></image-component>
        </div>
    <script>
       window.Laravel = <?php echo json_encode([
           'csrfToken' => csrf_token(),
        ]); ?>
    </script>
    <script src="{{asset('js/app.js')}}"></script>
    </body>
</html>

Start the Laravel development server with the following command.

php artisan serve

Switch to the following URL.

http://localhost:8000

See the below image.

Vue File Upload Tutorial

Step 8: Create a form to upload an image.

In the ImageuploadComponent.vue file, write the following code into it.

// ImageuploadComponent.vue

<template>
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card card-default">
                    <div class="card-header">File Upload Component</div>
                    <div class="card-body">
                       <div class="row">
                          <div class="col-md-9">
                              <input type="file" v-on:change="onImageChange" class="form-control">
                          </div>
                          <div class="col-md-3">
                             <button class="btn btn-success btn-block" @click="uploadImage">Upload Image</button>
                          </div>
                       </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        
    }
</script>

In this component, we have used an event and function, which we have not defined yet, so let us do that first.

// ImageuploadComponent.vue

<template>
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card card-default">
                    <div class="card-header">File Upload Component</div>
                    <div class="card-body">
                       <div class="row">
                          <div class="col-md-3" v-if="image">
                              <img :src="image" class="img-responsive" height="70" width="90">
                           </div>
                          <div class="col-md-6">
                              <input type="file" v-on:change="onImageChange" class="form-control">
                          </div>
                          <div class="col-md-3">
                             <button class="btn btn-success btn-block" @click="uploadImage">Upload Image</button>
                          </div>
                       </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        data(){
            return {
                image: ''
            }
        },
        methods: {
            onImageChange(e) {
                let files = e.target.files || e.dataTransfer.files;
                if (!files.length)
                    return;
                this.createImage(files[0]);
            },
            createImage(file) {
                let reader = new FileReader();
                let vm = this;
                reader.onload = (e) => {
                    vm.image = e.target.result;
                };
                reader.readAsDataURL(file);
            },
            uploadImage(){
                axios.post('/image/store',{image: this.image}).then(response => {
                   console.log(response);
                });
            }
        }
    }
</script>
Note: We are sending the base 64 binary to the server. So we need to make an image from that. We will use the Image intervention package to do that, so let us first install that.

Step 9: Install the image/intervention package.

Go to your terminal and type the following command to install the intervention/image package.

composer require intervention/image

After installing the package, we need to configure it into Laravel. So first, go to the config  >>  app.php file and register the Intervention Image Provider.

// app.php

'providers' => [
 Intervention\Image\ImageServiceProvider::class,
];

'aliases' => [
 'Image' => Intervention\Image\Facades\Image::class,
]

After this step, we need to publish the package by the following command.

php artisan vendor:publish --provider="Intervention\Image\ImageServiceProviderLaravel5"

We can use this package in our ImageController.php file.

Step 10: Code the store function.

Write the following code into the ImageController.php file.

// ImageController.php

    public function store(Request $request)
    {
       if($request->get('image'))
       {
          $image = $request->get('image');
          $name = time().'.' . explode('/', explode(':', substr($image, 0, strpos($image, ';')))[1])[1];
          \Image::make($request->get('image'))->save(public_path('images/').$name);
        }

       $image= new FileUpload();
       $image->image_name = $name;
       $image->save();

       return response()->json(['success' => 'You have successfully uploaded an image'], 200);
     }

Step 11: Finish our project.

Our UI looks like this.

Laravel Vue Image Upload Tutorial

Our final ImageuploadComponent.vue file looks like this.

// ImageuploadComponent.vue

<template>
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card card-default">
                    <div class="card-header">File Upload Component</div>
                    <div class="card-body">
                       <div class="row">
                          <div class="col-md-3" v-if="image">
                              <img :src="image" class="img-responsive" height="70" width="90">
                           </div>
                          <div class="col-md-6">
                              <input type="file" v-on:change="onImageChange" class="form-control">
                          </div>
                          <div class="col-md-3">
                             <button class="btn btn-success btn-block" @click="uploadImage">Upload Image</button>
                          </div>
                       </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        data(){
            return {
                image: ''
            }
        },
        methods: {
            onImageChange(e) {
                let files = e.target.files || e.dataTransfer.files;
                if (!files.length)
                    return;
                this.createImage(files[0]);
            },
            createImage(file) {
                let reader = new FileReader();
                let vm = this;
                reader.onload = (e) => {
                    vm.image = e.target.result;
                };
                reader.readAsDataURL(file);
            },
            uploadImage(){
                axios.post('/image/store',{image: this.image}).then(response => {
                   if (response.data.success) {
                     alert(response.data.success);
                   }
                });
            }
        }
    }
</script>

You can check it out!

Fork Me On Github

5 thoughts on “Laravel Vue File Upload Example”

  1. hi,

    i got this error when upload file:

    “message”: “Can’t write image data to path (C:\\xampp\\htdocs\\vue-app\\public\\images/1521536190.jpeg)”,
    “exception”: “Intervention\\Image\\Exception\\NotWritableException”,
    “file”: “C:\\xampp\\htdocs\\vue-app\\vendor\\intervention\\image\\src\\Intervention\\Image\\Image.php”,
    “line”: 143,
    “trace”: [
    {
    “file”: “C:\\xampp\\htdocs\\vue-app\\app\\Http\\Controllers\\ImageController.php”,
    “line”: 16,
    “function”: “save”,
    “class”: “Intervention\\Image\\Image”,
    “type”: “->”
    },

    Reply
  2. hi,
    thank you about pulish this article, but have question please, you use vm instance and set image data but this value just have value in inner scope and actuly after this scope {vm.image = …} image get default value empty

    can you choose better way to set vm.image globaly not locally?

    Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.