Categories: AngularJSLaravelPHP

Incredible Laravel 5 Angular JS File Upload

In this tutorial I am going give an example on how to upload file, list files, delete file in Laravel 5 using AngularJS

You can also learn File Upload using jQuery and PHP – PHP and Ajax Asynchronous File Upload using jQuery

Tutorial Features:

A very simple demo application with bootstrap design, which is having feature to select a file and upload to server to desire locations, I have added little bit more usable features to this tutorial those are listed below:

  • File upload validations such as Required, File Type and File size
  • Find the file type
  • Calculating and store the size of the file
  • Renaming file while uploading on to the server
  • Listing existing files from the server
  • Delete file from server

Here is quick Look of the tutorial demo:

Work environment requirements:

You should have following basic server requirements ready to run Laravel application, for more information on Laravel installation you can visit to Laravel.com documentation section.

  • PHP >= 5.6.4
  • MySQL
  • Apache/nginx
  • PDO Extension
  • OpenSSL
  • Mbstring
  • XML
  • Tokenizer

Step 1 – Create Laravel Application:

Let’s start by creating new Laravel application use following command to create new Laravel application on your local development server.

Using Laravel Installer:

laravel new laravel-5-angularjs-file-upload

OR

If you don’t have Laravel installer, you can use composer to create the application:

composer create-project --prefer-dist laravel/laravel laravel-5-angularjs-file-upload

Step 2- Create Database and update connection settings from .env file :

Go a head and create a database within MySQL and update the connection setting from .env file as showing below:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=YOUR_DATABASE_NAME
DB_USERNAME=DATABASE_USERNAME
DB_PASSWORD=DATABASE_USER_PASSWORD

So now we have our database connection ready to work, move on to the next step and start migrating a database table to store files.

You can also learn How to work with AngularJS Crud Operations – AngularJS PHP CRUD (Create, Read, Update, Delete) Operations

Step 3 – Database Migration:

Use following command to generate new migration file and add required columns:

php artisan make:migration create_files_table --create=files

Open up the migration file into your editor and update it according to the following script:

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateFilesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */    public function up()
    {
        Schema::create('files', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->integer('size');
            $table->string('type');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */    public function down()
    {
        Schema::dropIfExists('files');
    }
}

Save file and run following artisan command to execute migration script, so that we can have our database table created.

php artisan migrate

You should see output similar to below text:

Migrating: 2017_06_22_074935_create_files_table
Migrated:  2017_06_22_074935_create_files_table

OR

You can also use following SQL script to create database table, this is optional step I always prefer to use Laravel migrations as they are easy to use and speed up the development process, anyways it depends on you at the end and your development environment.

CREATE TABLE `files` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `size` int(11) NOT NULL,
  `type` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Step 4 – Setup Controller, Blade Template Page and Route:

In this step we are actually going to setup a User Interface where user can upload file, see list of existing uploaded files and be able to delete file, go ahead and open you terminal and run following command to create new `FilesController` for our application.

php artisan make:controller FilesController

FileController should be ready and can be located in – `/app/Http/Controllers/FilesController.php`

Next we need to add method under FileController Class to load application view, go ahead and open up FileController.php file in you editor and add following method:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class FilesController extends Controller
{
    /**
     * Load Files View
     * 
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */    public function files()
    {
        return view('files');
    }
}

If you see in the above code we have a method called `files()` and it’s returning a view which is currently not there in the application so we need to add that, let a new file named `files.blade.php` under `/resources/views/files.blade.php` don’t forget to add `.blade.php` extension at the end of the file.

Open up the files.blade.php file in your editor to add basic html code to design our file upload view:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Laravel 5 AngularJS File Upload</title>

    {{-- Application CSS File --}}
    <link rel="stylesheet" href="css/app.css">
</head>
<body>

<div class="container">
    <div class="row">
        <div class="col-md-12">
            <h2>Laravel 5 AngularJS File Upload Demo</h2>
        </div>
    </div>

    <div class="row">
        <div class="col-md-12">
            <div class="form-group">
                <label for="files">Select Image File</label>
                <input type="file" name="files" id="files" class="form-control">
            </div>
            <div class="form-group">
                <button class="btn btn-primary">Upload File</button>
            </div>
        </div>
    </div>
</div>

{{-- Application JS Files --}}
<script src="js/app.js"></script>
</body>
</html>

If you notice the above code starting from the head section you will see I added css file which is laravel default application css file which comes along with bootstrap css so no needs to worry about installing bootstrap framework, next in the body section I added a html design with heading tag to name the application and a file element along with file label and a button to upload a file, keep in mind this is not a final design.

Next you need to setup route to up the page that we just designed, so open the `web.php` route file from `/routes` directory  and make following changes:

Replace Default `/` route to the following:

`/routes/web.php`:

<?php

Route::get('/', 'FilesController@files');

If you try to run the application in your browser you should see the following output:

Step 5 – Setup AngularJS,  Setup Module and Directive

There are two methods available to install AngularJS into your application, first is using NodeJS NPM install along with webpack laravel provides webpack complete setup to work, you just needs to have NodesJS installed into your development server, second step is to simply calling `angularjs.min.js` file from your template file anyways here I we are going to use second step as just to make sure every user has to take advantages of using this tutorial.

Before starting to setup our files view, make sure you have angularjs.min.js file ready if not you can easily visit angularjs.org and download latest angularjs file.

Next create blank `script.js` file inside `public/js/` directory, this is the file where we are going to write our client side script to handle file upload operations.

Now let’s start by setting up our `files.blade.php` page with AngularJS, open up files.blade.php page to your editor and update it according to the following code:

`files.blade.php:`

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Laravel 5 AngularJS File Upload</title>

    {{-- Application CSS File --}}
    <link rel="stylesheet" href="css/app.css">
</head>
<body ng-app="App">

<div ng-controller="FileUploadController">

    <div class="container">
        <div class="row">
            <div class="col-md-12">
                <h2>Laravel 5 AngularJS File Upload Demo</h2>
            </div>
        </div>

        <div class="row">
            <div class="col-md-12">
                <div class="form-group">
                    <label for="files">Select Image File</label>
                    <input type="file" name="files" id="files" class="form-control">
                </div>
                <div class="form-group">
                    <button class="btn btn-primary">Upload File</button>
                </div>
            </div>
        </div>
    </div>

</div>

{{-- Application JS Files --}}
<script src="js/app.js"></script>
<script src="js/angular.min.js"></script>
<script src="js/script.js"></script>

</body>
</html>

Have a look on above code at the bottom to the page, we have added new JS files for AngularJS, and in the body section we have `ng-app` define to initialise the AngularJS scope for the application and then within the body section I have added new div element along with the `ng-controller` attribute, so now we have started using `ng` attributes in side our view, let’s start by updating our newly created script.js file to define module controller and directive.

`script.js:`

var app = angular.module('App', []);

app.controller('FileUploadController', ['$scope', '$http', function ($scope, $http) {

}]);

app.directive('ngFiles', ['$parse', function ($parse) {

    function file_links(scope, element, attrs) {
        var onChange = $parse(attrs.ngFiles);
        element.on('change', function (event) {
            onChange(scope, {$files: event.target.files});
        });
    }

    return {
        link: file_links
    }
}]);

Step 6 – Create Eloquent Model

As I said we are going to deal with the database to add new record when user upload a new file, read and delete existing records, for all this operation we will need a Laravel Model let’s create it and required properties into it

Open your terminal(command line for windows user) and run this command to create new model:

php artisan make:model File

Open newly created model file in your editor which is located at `app/File.php` location and it according to the below file:

`app/File.php`

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class File extends Model
{
    protected $fillable = [
        'name',
        'size',
        'type'
    ];
}

Step 7 – Add Controller Methods to handle file operations:

So we are almost ready to access eloquent model and write our methods into the files controller, go ahead and open up the `FilesController` from the `app/Http/Controllers/FilesController.php` directory and update it according to the following script:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\File;
use Symfony\Component\HttpKernel\Tests\Debug\FileLinkFormatterTest;
use Validator;
use Illuminate\Support\Facades\Storage;

class FilesController extends Controller
{
    /**
     * Load Files View
     *
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */    public function files()
    {
        return view('files');
    }

    /**
     * List Uploaded files
     *
     * @return array
     */    public function listFiles()
    {
        return ['files' => File::all()];
    }


    /**
     * Upload new File
     *
     * @param Request $request
     *
     * @return \Illuminate\Http\JsonResponse
     */    public function upload(Request $request)
    {
        $validator = Validator::make($request->file(), [
            'image_file' => 'required|image|max:50',
        ]);

        if ($validator->fails()) {

            $errors = [];
            foreach ($validator->messages()->all() as $error) {
                array_push($errors, $error);
            }

            return response()->json(['errors' => $errors, 'status' => 400], 400);
        }

        $file = File::create([
            'name' => $request->file('image_file')->getClientOriginalName(),
            'type' => $request->file('image_file')->extension(),
            'size' => $request->file('image_file')->getClientSize(),
        ]);

        $request->file('image_file')->move(__DIR__ . '/../../../image_uploads/', $file->id . '.' . $file->type);

        return response()->json(['errors' => [], 'files' => File::all(), 'status' => 200], 200);
    }

    /**
     * Delete existing file from the server
     *
     * @param Request $request
     *
     * @return \Illuminate\Http\JsonResponse
     */    public function delete(Request $request)
    {
        Storage::delete(__DIR__ . '/../../../image_uploads/' . $request->input('id'));

        File::find($request->input('id'))->delete();

        return response()->json(['errors' => [], 'message' => 'File Successfully deleted!', 'status' => 200], 200);
    }
}

Let’s Discuss about file in details to understand each and every function and it’s job:

`file()` – Use to load files view

`listFiles()` – as name suggest it is used to list all existing files and if you look at the function it is having a statement where we are calling model to access the records from the database.

`upload()` – use to handle upload file request, it does operations like validate the file according to the given rules such as to check whether file is an image file, check out the size file to not exceed more 50 kilobyte and next store new record into the database and upload file on to the given location and rename the file with the database record id to keep in track of uploaded file.

`delete()` – handle delete file request, it accepts the input as file id and performs the operations like delete file from the directory as well as delete the file record from the database.

Next.. create `image_uploads` folder inside root directory, if you forgot to create a directory laravel still does the job it will create a directory by it’s own while upload first file.

Step 8 – Add CSRF-TOKEN to the AngularJS http/ajax requests

As we know laravel handles cross site request forgery attack to protect our application, and we need to take care about sending CSRF Token while performing server side operations, in this step we will add CSRF token to the AngularJS script using `$httpProvider`, open up the script.js file and update module declaration according to the following script:

var app = angular.module('App', [], ['$httpProvider', function ($httpProvider) {
    $httpProvider.defaults.headers.post['X-CSRF-TOKEN'] = $('meta[name=csrf-token]').attr('content');
}]);

Note: we will need to update our files.blade.php file to have new meta tag called `csrf-token` with content value, we will do that in further steps.

Step 9 – Update AngularJS controller:

Update controller with the below script to have our client script ready:

app.controller('FileUploadController', ['$scope', '$http', '$window', function ($scope, $http) {

    $scope.errors = [];

    $scope.files = [];

    $scope.listFiles = function () {
        var request = {
            method: 'GET',
            url: '/file/list',
            headers: {
                'Content-Type': undefined
            }
        };

        $http(request)
            .then(function success(e) {

                $scope.files = e.data.files;

            }, function error(e) {

            });
    };

    $scope.listFiles();

    var formData = new FormData();

    $scope.uploadFile = function () {

        var request = {
            method: 'POST',
            url: '/upload/file',
            data: formData,
            headers: {
                'Content-Type': undefined
            }
        };

        $http(request)
            .then(function success(e) {
                $scope.files = e.data.files;
                $scope.errors = [];
                // clear uploaded file
                var fileElement = angular.element('#image_file');
                fileElement.value = '';
                alert("Image has been uploaded successfully!");
            }, function error(e) {
                $scope.errors = e.data.errors;
            });
    };

    $scope.setTheFiles = function ($files) {
        angular.forEach($files, function (value, key) {
            formData.append('image_file', value);
        });
    };

    $scope.deleteFile = function (index) {
        var conf = confirm("Do you really want to delete this file?");

        if (conf == true) {
            var request = {
                method: 'POST',
                url: '/delete/file',
                data: $scope.files[index]
            };

            $http(request)
                .then(function success(e) {
                    $scope.errors = [];

                    $scope.files.splice(index, 1);

                }, function error(e) {
                    $scope.errors = e.data.errors;
                });
        }
    };

}]);

You will notice we have different controller functions those sending a post or get request to server to performs operations but our server not ready yet or we can say our routes is not defined yet request controller method  let move on to the next step to update routes file.

Step 10 – Update Routes:

go ahed and open up the web.php file from routes folder and update it according to the below script:

<?php


Route::get("/", "FilesController@files");

Route::post("upload/file", "FilesController@upload");

Route::get('/file/list', 'FilesController@listFiles');

Route::post("/delete/file

Step 11 – Update Template file

Finally we are there now we just need to update our template file to complete our demo application, so in this file first thing I am updating the head part to have our laravel csrf token ready to use, next updated the input file element by adding ng-files directive, added file upload function call with ng-click event on button click, listed the error if found and at last listed all files along with the button to handle delete event.

go ahed and open up files.blade.php file and update it according to the following script.

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Laravel 5 AngularJS File Upload</title>

    {{-- Application CSS File --}}
    <link rel="stylesheet" href="css/app.css">

    <!-- Scripts -->
    <script>
        window.Laravel = <?php echo json_encode([
                'csrfToken' => csrf_token(),
        ]); ?>
    </script>
</head>
<body ng-app="App">

<div ng-controller="FileUploadController">

    <div class="container">
        <div class="row">
            <div class="col-md-12">
                <h2>Laravel 5 AngularJS File Upload Demo</h2>
            </div>
        </div>

        <div class="row">
            <div class="col-md-12">
                <div class="form-group">
                    <label for="files">Select Image File</label>
                    <input type="file" ng-files="setTheFiles($files)" id="image_file"  class="form-control">
                </div>

                <ul class="alert alert-danger" ng-if="errors.length > 0">
                    <li ng-repeat="error in errors">
                        @{{ error }}
                    </li>
                </ul>

                <div class="form-group">
                    <button ng-click="uploadFile()" class="btn btn-primary">Upload File</button>
                </div>
            </div>
        </div>

        <div class="row">
            <div class="col-md-12">
                <h4>Uploaded Files</h4>
                <table ng-if="files.length > 0" class="table table-bordered table-striped">
                    <tr>
                        <th>No.</th>
                        <th>Name</th>
                        <th>Size</th>
                        <th>Type</th>
                        <th>Uploaded On</th>
                        <th>Delete</th>
                    </tr>
                    <tr ng-repeat="file in files">
                        <td>@{{ $index + 1 }}</td>
                        <td>@{{ file.name }}</td>
                        <td>@{{ file.size }}</td>
                        <td>@{{ file.type }}</td>
                        <th>
                            @{{ file.created_at }}
                        </th>
                        <td>
                            <button ng-click="deleteFile($index)" class="btn btn-danger">Delete File</button>
                        </td>
                    </tr>
                </table>
                <div class="alert alert-success" ng-if="files.length == 0">
                    Files not found, please upload to test the demo application.
                </div>
            </div>
        </div>
    </div>

</div>

{{-- Application JS Files --}}
<script src="js/app.js"></script>
<script src="js/angular.min.js"></script>
<script src="js/script.js"></script>

</body>
</html>

we are done, go ahed and run your code into the browser to test the application.

If you need complete source code clone from our Github repository – https://github.com/itechempires/laravel-5-angularjs-file-upload

Let me know if you have any questions related to this tutorial using comment box below.

 

Happy Coding!

Want to Learn Multiple file upload with Drag and Drop Support? you ca visit this tutorial – Perfect use of Dropzone with Laravel and AngularJS

Yogesh Koli

Software engineer & Blogger live in India, has 8+ years of experience working with the Front-end and Back-end Web Application Development.

Recent Posts

Complete guide of using Laravel 6 Eloquent Subquery Enhancements

Learn How to use laravel frameworks new improved feature called Eloquent Subquery and get example…

2 years ago

3 Useful examples of using Array Map function in PHP – Best Practices

Learn how to use php array map function with easy and essential tutorial to modify…

2 years ago

Working with PHP Array Filter Function – Best Practices

Learn how to use php array filter function with easy and essential tutorial to filter…

2 years ago

How to add Access Modifiers with Constructor Parameters in TypeScript

Want to know how to refactor your Typescript class, Learn here utilising Typescript of the…

2 years ago

What is Access Modifiers and how to use Access Modifiers in TypeScript ?

What is Access Modifiers in typescript, how to use Access Modifiers, when to use them,…

2 years ago

Top 10 Super Useful Packages to Improve Laravel applications in 2019

This tutorial provide ultimate list of package those are top 10 on packagist and super…

2 years ago