In a lot of our projects we need to make a multiple image uploader. In this tutorial, We will make an advanced AJAX uploader. This uploader will:
- upload multiple images via AJAX.
- show the thumbnails of those uploads using Dropzone.js
- show the URL link of the uploaded images and copy it to the clipboard using clipboardjs.
Let’s start !
The Controller:
First of all, let’s make a controller for our upload function:
php artisan make:controller UploadController
let’s write our upload function (each line explained)
public function upload(Request $request)
{
// Creating a new time instance, we'll use it to name our file and declare the path
$time = Carbon::now();
// Requesting the file from the form
$image = $request->file('file');
// Getting the extension of the file
$extension = $image->getClientOriginalExtension();
// Creating the directory, for example, if the date = 18/10/2017, the directory will be 2017/10/
$directory = date_format($time, 'Y') . '/' . date_format($time, 'm');
// Creating the file name: random string followed by the day, random number and the hour
$filename = str_random(5).date_format($time,'d').rand(1,9).date_format($time,'h').".".$extension;
// This is our upload main function, storing the image in the storage that named 'public'
$upload_success = $image->storeAs($directory, $filename, 'public');
// If the upload is successful, return the name of directory/filename of the upload.
if ($upload_success) {
return response()->json($upload_success, 200);
}
// Else, return error 400
else {
return response()->json('error', 400);
}
}
As we can see, we store the file using storeAs , in the storage that named public . that can be customized from config/filesystems you’ll see a public system there, I changed it to look like this:
'public' => [
'driver' => 'local',
'root' => public_path('uploads'),
'url' => env('APP_URL').'/uploads',
'visibility' => 'public',
]
This way, the files will be uploaded to public/uploads/ .
The Route:
In our routes/web
file will add this post route which will go to our controller:
Route::post('/upload' , 'UploadController@upload');
The View:
let’s make a blade file that contains our uploader and its javascript functions:
in head section in our blade file, we’ll add Dropzone.js dependencies:
<script src="{{url('js/dropzone.js')}}"></script>
<link rel="stylesheet" href="{{url('css/dropzone.css')}}">
Next, we’ll create the uploading form:
<form action="{{ url('/admin/upload') }}" enctype="multipart/form-data" class="dropzone" id="my-dropzone">
{{ csrf_field() }}
</form>
Notice that we added csrf_field()
. The form will not work properly without it!
now, let’s start adding the footer scripts:
First, let’s add clipboardjs script, which we’ll be using to copy the URL of the uploaded images
The first script will be the upload script:
<script>
Dropzone.options.myDropzone = {
paramName: 'file',
maxFilesize: 5, // MB
maxFiles: 20,
acceptedFiles: ".jpeg,.jpg,.png,.gif",
init: function() {
this.on("success", function(file, response) {
var a = document.createElement('span');
a.className = "thumb-url btn btn-primary";
a.setAttribute('data-clipboard-text','{{url('/uploads')}}'+'/'+response);
a.innerHTML = "copy url";
file.previewTemplate.appendChild(a);
});
}
};
</script>
If you want to stop right here, and you don’t need to copy the URLs, you can delete the init function from the above script init:function(){...} and you’ll be done! In the above script, specifically on success function, we can see that we made a variable a which is a span that will be embedded after each uploaded thumbnail.
This span has a class thumb-url and a new attribute that called data-clipboard-text which contains the response from our upload function. Our span also has the classes btn btn-primary , those are boostrap classes, we will be using bootstrap to show the tooltip when the user click to copy the URL.
Let’s add the clipboard js:
<script src="{{url('js/clipboard.min.js')}}"></script>
Now let’s write our function:
<script>
$('.thumb-url').tooltip({
trigger: 'click',
placement: 'bottom'
});
function setTooltip(btn, message) {
$(btn).tooltip('hide')
.attr('data-original-title', message)
.tooltip('show');
}
function hideTooltip(btn) {
setTimeout(function() {
$(btn).tooltip('hide');
}, 500);
}
var clipboard = new Clipboard('.thumb-url');
clipboard.on('success', function(e) {
e.clearSelection();
setTooltip(e.trigger, 'Copied!');
hideTooltip(e.trigger);
});
clipboard.on('error', function(e) {
e.clearSelection();
setTooltip(e.trigger, 'Failed');
hideTooltip(e.trigger);
});
</script>
This way, when the user click on the copy button, it will show a tooltip that says copied! and the URL will be copied to the clipboard! I hope you find this tutorial helpful
Nice coding! 🌹
Comments