Table of Contents
# Introduction:
This article covers the complete steps to understand and use of Dropzone JS, Dropzone is really flexible and specifically improves file uploading feature for end user, It enables drag and drop option while uploading a file, so it is always good to implement drop zone JS into the application when we require to handle file upload.
Recently I have realsed a tutorial on Laravel File AngularJS upload, if you want to learn handling file upload in Laravel framework and AngulaJS only then you can read previous tutorial before going to handle this tutorial.
In this tutorial we be developing a file upload demo with Laravel 5.6 and AngularJS and our demo will have following list of features:
- Upload multiple files by dragging and dropping on dropzone box
- Store records for each uploaded file into the database
- List all uploaded files
- Delete exiting file from directory as well a associated record from the database
By reading this tutorial you will learn use of dropzone library with AngularJS and Laravel framework.
So let’s begin:
# Project Setup
In this step we are going to create new Laravel project and setup database settings along with creating new database (will be using MySQL database).
If you already have your existing project, you can skip this step and start from the next step onwards to implement drag and drop feature into your project.
Create new project using Laravel installer or Composer:
$ laravel new laravel-dropzonejs-file-upload
OR
$ composer create-project --prefer-dist laravel/laravel laravel-dropzonejs-file-upload
Database Settings:
Open up your project into your code editor, in my case I am using visual studio code.
Next go ahead and open .env file and update add database name, the database username and password.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel-dropzone
DB_USERNAME=root
DB_PASSWORD=
Create new database
Open MySQL and create new database as you have mentioned in the above step.
# Create Database Migration and Eloquent Model
We are going to need a database migration file to create new table into the database and a eloquent model file to handle database operations.
To generate both files use following artisan command
$ php artisan make:model File -m
You should have create_files_table and File.php files generated
Open up File.php file into code editor from app/ directory and add guarded property as all Eloquent models protect against mass-assignment.
File.php:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class File extends Model
{
protected $guarded = [];
}
Next update migration file and add new fields as showing below
<?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->string('size');
$table->string('extention');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('files');
}
}
Now migrate the database to create files table using command given below:
$ php artisan migrate
We are all set about the database setup in next step let’s focus on angularjs and dropzone installation.
# AngularJS, Dropzone installation and Setup into Laravel:
To handle this step you should have node package manager installed into your system so that you can install required dependencies and compile your front end code with Laravel mix.
To install npm you can simply install Node.Js from nodejs.org, npm comes along the nodejs.
okay so now I assume that you have npm installed and ready to use.
Note – if you haven’t installed node dependencies for your Laravel project then use following command to install them first.
$ npm install
Wait until your get all the dependencies installed, you should get message showing below when the installation process is complete:
added 1260 packages from 716 contributors and audited 8994 packages in 49.728s
found 0 vulnerabilities
Next install angularjs
$ npm install angular --save-dev
Now install dropzone using following command
$ npm install dropzone --save
Open bootstrap.js file from /resources/assets/js/ and replace it with the script given below:
/resources/assets/js/bootstrap.js:
window._ = require('lodash');
window.Popper = require('popper.js').default;
try {
window.$ = window.jQuery = require('jquery');
require('bootstrap');
} catch (e) {}
// Import AngularJS and Dropzone JS
import 'angular';
import dropzone from 'dropzone';
// Declare Dropzone to use globaly into the project
window.dropzone = dropzone;
If you notice above code, you will see that we have imported angular as well as dropzone, also take a note we are declaring dropzone globally so that we can use anywhere int the project using window object.
Next open up app.scss file from /resources/assets/sass/ directory and a line to import dropzone css file. as showing below script
/resources/assets/sass/app.scss:
// Fonts
@import url('https://fonts.googleapis.com/css?family=Nunito');
// Variables
@import 'variables';
// Bootstrap
@import '~bootstrap/scss/bootstrap';
// Dropzone CSS
@import '~dropzone/dist/dropzone.css';
.navbar-laravel {
background-color: #fff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
}
Now are are good with angularjs and dropzone installation, next will have to use into into our JS, but before going to do that, first let’s design our front end view.
# Design Frontend View
In this step we will design a view, the view will have a dropzone box along with list of uploaded files.
Go ahed and open welcome.blade.php view from /resources/views/ directory. You can use different file if you are using existing project don’t get confuse.
Replace view following script, If notice the script basically we are setting up the page structure along with AngularJS module and controller setup.
Don’t forget to note the window.laravel declaration here, this is the important variable we are going to use this token while handling http/xhr requests from front end. without this the project will not work.
/resources/views/welcome.blade.php:
<!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>Laravel AngularJS file Upload with dropzone</title>
<link rel="stylesheet" href="css/app.css">
<script>
window.Laravel = <?php echo json_encode([
'csrfToken' => csrf_token(),
]); ?>
</script>
</head>
<body ng-app="App">
<div ng-controller="FileUploadController" ng-clock>
// Rest of the further script will be here
</div>
<script src="js/app.js"></script>
</body>
</html>
Next add following script into the same above page and it should go into the ng-controller section:
<div class="container">
<div class="row">
<div class="col">
<br>
<h1>Laravel AngularJS file Upload with dropzone</h1>
<hr>
{{-- Dropzone --}}
<div class="dropzone" mydropzone options="options" callbacks="callbacks" methods="methods"></div>
<br>
<h2>All Uploaded Files</h2>
{{-- File Listing --}}
<div class="table-responsive-sm">
<table class="table table-bordered">
<thead>
<tr>
<th scope="col">No</th>
<th scope="col">Image</th>
<th scope="col">Name</th>
<th scope="col">Remove</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="file in allFiles" ng-if="allFiles.length > 0">
<td>@{{ $index + 1 }}</td>
<td><img height="100" ng-src="/images/@{{ file.id }}.@{{ file.extention }}"></td>
<td>
@{{ file.name }}
</td>
<td>
<button ng-click="deleteFile(file, $index)" class="btn btn-outline-danger btn-sm">X</button>
</td>
</tr>
<tr ng-if="allFiles.length == 0">
<td colspan="5">
Files not found!
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
If read above script carefully you will have we have number of things written up there, the page title, dropzone implementation along with custom directive and also lopping files into the html table with different columns.
# AngularJS Controller and Custom Directive for dropzone
This specifically important step, in this step we are going define our AngularJS controller along with the a directive fro dropzone, the directive will ensure the few things such as render dropzone, bind events and methods.
Go ahead and open app.js file from /resources/assets/js/ folder and replace with the following script
/resources/assets/js/app.js:
import './bootstrap';
var app = angular.module('App', [], ['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.headers.post['X-CSRF-TOKEN'] = Laravel.csrfToken;
}]);
app.controller('FileUploadController', ['$scope', '$http', function ($scope, $http) {
// Store all the files
$scope.allFiles = [];
// load files from the server
$scope.loadAllFiles = function()
{
$http.get('/all-files').then(function success(e) {
$scope.allFiles = e.data.files;
});
};
$scope.loadAllFiles();//
// dropzone configuration, the url and headers part is important make sure to focus on this
$scope.options = {
url: '/upload-file',
maxFilesize: 100,
acceptedFiles: 'image/jpeg, images/jpg, image/png',
headers: { 'X-CSRF-TOKEN': Laravel.csrfToken}
};
$scope.callbacks = {
'addedfile': function (file) {
// can add more action if needed when user add new file to upload
},
'success': function (file, xhr) {
// file got successfully uploaded
$scope.allFiles.push(xhr.file);
},
'removedfile': function(file){
// Dropzone remove file event
},
uploadprogress: function (file, progress, bytesSent) {
// Display file uploading progress
}
};
// Remove file from server
$scope.deleteFile = function(file, index)
{
$http.post('/delete-file', {id: file.id}).then(function success(e) {
$scope.allFiles.splice(index, 1);
});
};
}]);
app.directive('mydropzone', function () {
return {
restrict: 'AE',
replace: true,
scope: {
options: '=?',
methods: '=?',
callbacks: '=?',
},
link: function (scope, el) {
Dropzone.autoDiscover = false;
var drop = new Dropzone(el[0], scope.options);
scope.methods = scope.methods || {};
scope.methods.getDropzone = function () {
return drop;
};
scope.methods.getAllFiles = function () {
return drop.files;
};
var controlMethods = [
'removeFile', 'removeAllFiles', 'processQueue',
'getAcceptedFiles', 'getRejectedFiles', 'getQueuedFiles', 'getUploadingFiles',
'disable', 'enable', 'confirm', 'createThumbnailFromUrl'
];
angular.forEach(controlMethods, function (methodName) {
scope.methods[methodName] = function () {
drop[methodName].apply(drop, arguments);
if (!scope.$$phase && !scope.$root.$$phase) scope.$apply();
};
});
if (scope.callbacks) {
var callbackMethods = [
'drop', 'dragstart', 'dragend',
'dragenter', 'dragover', 'dragleave', 'addedfile', 'removedfile',
'thumbnail', 'error', 'processing', 'uploadprogress',
'sending', 'success', 'complete', 'canceled', 'maxfilesreached',
'maxfilesexceeded', 'processingmultiple', 'sendingmultiple', 'successmultiple',
'completemultiple', 'canceledmultiple', 'totaluploadprogress', 'reset', 'queuecomplete'
];
angular.forEach(callbackMethods, function (method) {
var callback = (scope.callbacks[method] || angular.noop);
drop.on(method, function () {
callback.apply(null, arguments);
if (!scope.$$phase && !scope.$root.$$phase) scope.$apply();
});
});
}
}
};
});
If you notice above script from the first line to last you will notice few important things going on here, details points are here:
- Import bootstrap.js file where we have added our external library files such as bootstrap, jquery, proper.js, angular and dropzone.
- AngularJS module declaration with http provider configuration to have new field added to the header called X-CSRF-TOKEN
- AngularJS Controller definition along with dropzone configuration and methods to load files from server as well as delete the file from the server
- Custom directive for dropzone called mydropzone – this important one read it carefully to understand the declaring, rendering and other configuration part such as events binding methods binding.
Recommended – Incredible Laravel 5 Angular JS File Upload
# Laravel Routes and Controller Setup
As we see we have complete all the front end part of the demo, now it’s time look at the backend where we are going to handle different request coming from the front end such as upload and store the file, list out the files and delete existing file.
To this let’s generate new controller and required define methods:
$ php artisan make:controller FileUploadsController
Open up FileUploadsController.php file and add following definiation:
<?php
/**!
* Laravel AngularJS file Upload using dropzone
* @author Yogesh Koli <yogesh@itechempires.com>
* https://www.itechempires.com
*/
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\File;
class FileUploadsController extends Controller
{
protected $file_upload_path;
public function __construct()
{
$this->file_upload_path = public_path('/images');
}
/**
* List all the files
*
* @return void
*/
public function list()
{
$files = File::all();
if (request()->wantsJson()) {
return response()->json(['files' => $files], 200);
}
return response(['files' => $files], 200);
}
/**
* Upload the file
*
* @return void
*/
public function upload()
{
$this->validate(request(), [
'file' => 'required|file'
]);
$request_file = request()->file('file');
$size = $request_file->getClientSize();
$extention = strtolower($request_file->getClientOriginalExtension());
$name = $request_file->getClientOriginalName();
$file = File::create([
'name' => $name,
'size' => $size,
'extention' => $extention,
]);
$request_file->move($this->file_upload_path, $file->id . '.' . $extention);
return response()->json(['file' => $file], 200);
}
/**
* Delete Given file
*
* @return void
*/
public function deleteFile()
{
$this->validate(request(), [
'id' => 'required'
]);
$file = File::find(request('id'));
unlink($this->file_upload_path . '/' . $file->id . '.' . $file->extention);
$file->delete();
return response()->json(['message' => 'Given file has been deleted'], 200);
}
}
Now will needs to define routes to align income requests, open web.php file and add following new routes:
<?php
Route::get('/', function () {
return view('welcome');
});
Route::get('/all-files', 'FileUploadsController@list');
Route::post('/upload-file', 'FileUploadsController@upload');
Route::post('/delete-file', 'FileUploadsController@deleteFile');
# Compile Assets using Laravel Mix:
We are almost done with the development part, now we just have compile the assets (the css and JS part) and test the project.
If you remember at the start of this tutorial I told your about npm and compile the assets with laravel mix.
Okay so you don’t have do much things you just needs to run following command and your done.
$ npm run dev
If you success message like this:
DONE Compiled successfully in 6202ms 17:24:35
Asset Size Chunks Chunk Names
/js/app.js 2.52 MB 0 [emitted] [big] /js/app
/css/app.css 206 kB 0 [emitted] /js/app
Then you can go ahead and test the demo into the browser, you should see output as showing into the screen below:
Try uploading single or multiple files and then try deleting files as well see the result.
All done, let me know if you get any issues using comment box below and keep sharing I Tech Empires tutorials to your friends on social media.