AJAX is an important part of web development. This blog post covers steps to handle AJAX images upload with progress bar in Bootstrap with drag n drop feature. Some cool features in these steps are:
- AJAX uploading images
- Nicely displays any error that occurred in Bootstrap style alert.
- Shows progress bar while uploading.
- Image preview after uploading.
- Automatic image upload on drag and drop or on image selection through file browser button.
- Bootstrap style file input button instead of a regular one.
- No external upload handling script is used.
- Using the famous Twitter Bootstrap front-end framework.
- Multiple images upload.
- Easily extensible.
- Regular File browser for outdated browsers.
- Extreme lightweight.
Drag n drop multiple AJAX images upload with progress bar in Bootstrap
Starting with a simple image drop zone, place the following markup at the desired location on your page.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <div class="container-fluid"> <div class="row"> <div class="col-sm-8 col-sm-offset-2"> <div class="img-zone text-center" id="img-zone"> <div class="img-drop"> <h2><small>Drag & Drop Photos Here</small></h2> <p><em>- or -</em></p> <h2><i class="glyphicon glyphicon-camera"></i></h2> <span class="btn btn-success btn-file"> Click to Open File Browser<input type="file" multiple="" accept="image/*"> </span> </div> </div> <div class="progress hidden"> <div style="width: 0%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="0" role="progressbar" class="progress-bar progress-bar-success progress-bar-striped active"> <span class="sr-only">0% Complete</span> </div> </div> </div> </div> <div id="img-preview" class="row"> </div> </div> |
So we have created an image area to drop and a progress bar below it. There is an image preview area as well to show the preview of images after uploading. Now let’s create some CSS rules to represent this drag n drop area in bootstrap style as shown in the featured image.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <style type="text/css"> .btn-file { position: relative; overflow: hidden; } .btn-file input[type=file] { position: absolute; top: 0; right: 0; min-width: 100%; min-height: 100%; font-size: 100px; text-align: right; filter: alpha(opacity=0); opacity: 0; outline: none; background: white; cursor: inherit; display: block; } .img-zone { background-color: #F2FFF9; border: 5px dashed #4cae4c; border-radius: 5px; padding: 20px; } .img-zone h2 { margin-top: 0; } .progress, #img-preview { margin-top: 15px; } </style> |
Now it’s time to apply some jQuery to actually handle AJAX image uploading. We have added the jQuery code in ajax-upload.js and you can download the zip at the end of this post. The code is placed here as well and we need to add the code or call the ajax-upload.js file after adding the necessary jQuery library in our project.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | jQuery(document).ready(function() { var img_zone = document.getElementById('img-zone'), collect = { filereader: typeof FileReader != 'undefined', zone: 'draggable' in document.createElement('span'), formdata: !!window.FormData }, acceptedTypes = { 'image/png': true, 'image/jpeg': true, 'image/jpg': true, 'image/gif': true }; // Function to show messages function ajax_msg(status, msg) { var the_msg = '<div class="alert alert-' + (status ? 'success' : 'danger') + '">'; the_msg += '<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>'; the_msg += msg; the_msg += '</div>'; $(the_msg).insertBefore(img_zone); } // Function to upload image through AJAX function ajax_upload(files) { $('.progress').removeClass('hidden'); $('.progress-bar').css({ "width": "0%" }); $('.progress-bar span').html('0% complete'); var formData = new FormData(); //formData.append('any_var', 'any value'); for (var i = 0; i < files.length; i++) { //formData.append('img_file_' + i, files[i]); formData.append('img_file[]', files[i]); } $.ajax({ url: "upload.php", // Change name according to your php script to handle uploading on server type: 'post', data: formData, dataType: 'json', processData: false, contentType: false, error: function(request) { ajax_msg(false, 'An error has occured while uploading photo.'); }, success: function(json) { var img_preview = $('#img-preview'); var col = '.col-sm-2'; $('.progress').addClass('hidden'); var photos = $('<div class="photos"></div>'); $(photos).html(json.img); var lt = $(col, photos).length; $('col', photos).hide(); $(img_preview).prepend(photos.html()); $(col + ':lt(' + lt + ')', img_preview).fadeIn(2000); if (json.error != '') ajax_msg(false, json.error); }, progress: function(e) { if (e.lengthComputable) { var pct = (e.loaded / e.total) * 100; $('.progress-bar').css({ "width": pct + "%" }); $('.progress-bar span').html(pct + '% complete'); } else { console.warn('Content Length not reported!'); } } }); } // Call AJAX upload function on drag and drop event function dragHandle(element) { element.ondragover = function() { return false; }; element.ondragend = function() { return false; }; element.ondrop = function(e) { e.preventDefault(); ajax_upload(e.dataTransfer.files); } } if (collect.zone) { dragHandle(img_zone); } else { alert("Drag & Drop isn't supported, use Open File Browser to upload photos."); } // Call AJAX upload function on image selection using file browser button $(document).on('change', '.btn-file :file', function() { ajax_upload(this.files); }); // File upload progress event listener (function($, window, undefined) { var hasOnProgress = ("onprogress" in $.ajaxSettings.xhr()); if (!hasOnProgress) { return; } var oldXHR = $.ajaxSettings.xhr; $.ajaxSettings.xhr = function() { var xhr = oldXHR(); if (xhr instanceof window.XMLHttpRequest) { xhr.addEventListener('progress', this.progress, false); } if (xhr.upload) { xhr.upload.addEventListener('progress', this.progress, false); } return xhr; }; })(jQuery, window); }); |
Here the code is self-explanatory and you can append more form data to pass to the server or can alter in your own way to best suit with your requirement.
The last part remaining is to accept the request at the server, validate the file, and move the uploaded file to a permanent location in the PHP script (upload.php). To simplify the steps, the minimum PHP code is as follow:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | <?php if($_SERVER['REQUEST_METHOD'] == "POST") { $error = ''; $img = ''; $dir = 'uploads/'; $extensions = array("jpeg","jpg","png"); foreach($_FILES['img_file']['tmp_name'] as $key => $tmp_name ) { $file_name = $_FILES['img_file']['name'][$key]; $file_size = $_FILES['img_file']['size'][$key]; $file_tmp = $_FILES['img_file']['tmp_name'][$key]; $file_type = $_FILES['img_file']['type'][$key]; $file_ext = explode('.', $file_name); $file_ext = strtolower(end($file_ext)); if(in_array($file_ext,$extensions ) === true) { if(move_uploaded_file($file_tmp, $dir.$file_name)) { $img .= '<div class="col-sm-2"><div class="thumbnail">'; $img .= '<img src="'.$dir.$file_name.'" />'; $img .= '</div></div>'; } else $error = 'Error in uploading few files. Some files couldn\'t be uploaded.'; } else { $error = 'Error in uploading few files. File type is not allowed.'; } } echo (json_encode(array('error' => $error, 'img' => $img))); } die(); ?> |
This PHP script is light and can explain the processing very well. It’s the same as a regular file upload. However, in a production environment, you must include more validation and code including file mime and size checking and renaming files to unique names before uploading and furthermore might need to create and return thumbnails of uploaded images.
Display Bootstrap Progress Bar in the Edge/IE Browsers
To make the Bootstrap progress bar in the Edge/IE browser. Add the following meta tag in the head section of your page. The first line is for the Edge and the rest all for Internet Explorer 8 and below.
1 2 3 4 5 6 | <meta http-equiv="X-UA-Compatible" content="IE=edge"> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]--> |
It’s all we require to handle drag n drop multiple AJAX images upload with progress bar in Bootstrap. Download the demo zip from here.
link download can’t used, bro..
link download not working
Good!
Really Thank you for your social help.
Why you don’t install Edge and fix the script? It would make lots of sense to offer your script to as good as it can possibly be. Thank you!
Hi @Matjaz
We will check the same sooner. Until would like to know what issue are you facing.
I was referring to your answer from 1 year ago (Unfortunately, I don’t have Edge browser to test in my desktop). Before I start implementing this, it would be nice if it is fixed, otherwise I cannot use it. I would appreciate if you install Edge and see why it is not working (as you are the author).
I just downloaded the zip and tested it – not working. I get this
An error has occured while uploading photo.
Hi @Matjaz
Yes! I hadn’t Edge at that time, now I have. By tomorrow, I will test the same and let you know.
In the meantime, you can also inspect the request in the developer console and the Network tab there.
Hi @Matjaz,
I’ve updated the code. There was a small issue with the newer PHP version.
Works great except in IE, the progression bar is not working… I tested on IE Edge
Hi @disqus_N4JQkb2PIY:disqus
Unfortunately, I don’t have Edge browser to test in my desktop. You could test the same using Edge Developer tool and let me know any error it reports.
thanks
An error has occured while uploading photo
why this error is apear from ajax_upload file
Hi,
you might have not uploads directory exist or not writable. Please check and let me know
thanks its great