I can’t seem to reach the end of the fun stuff you can do with web technologies. Today, I’m going to show you how to upload files via AJAX.
First, we'll see how to upload files using vanilla JavaScript. And later on, I'll show how you could use the DropzoneJS library to implement drag-and-drop file uploads.
Looking for a Quick Solution?
If you're looking for a quick solution, there's a great collection of file upload scripts and applications over at CodeCanyon.
How to Upload a File With Vanilla JavaScript
There are three main components to our project.
- The
multiple
attribute on the fileinput
element. - The
FileReader
object from the new File API. - The
FormData
object fromXMLHttpRequest
.
We use the multiple
attribute to allow the user to select multiple files for upload (multiple file upload will work normally even if FormData
isn’t available). As you’ll see, FileReader
allows us to show the user thumbnails of the files they’re uploading (we’ll be expecting images).
For older browsers that don't support FormData
or FileReader
, the upload behavior will fall back to a normal, non-AJAX file upload.
With that out of the way, let’s get coding!
Step 1: The Markup and Styling
Let’s start with some basic markup and styling. Of course, this isn’t the main part of this tutorial, I won’t treat you like a newbie.
The HTML
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>HTML5 File API</title> <link rel="stylesheet" href="style.css" /> </head> <body> <div id="main"> <h1>Upload Your Images</h1> <form method="post" enctype="multipart/form-data" action="upload.php"> <input type="file" name="images" id="images" multiple /> <button type="submit" id="btn">Upload Files!</button> </form> <div id="response"></div> <ul id="image-list"> </ul> </div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script> <script src="upload.js"></script> </body> </html>
Pretty basic, eh? We’ve got a form that posts to upload.php, which we’ll look at in a second, and a single input element, of type file
. Notice that it has the boolean multiple
attribute, which allows the user to select multiple files at once.
That’s really all there is to see here. Let’s move on.
The CSS
body { font: 14px/1.5 helvetica-neue, helvetica, arial, san-serif; padding:10px; } h1 { margin-top:0; } #main { width: 300px; margin:auto; background: #ececec; padding: 20px; border: 1px solid #ccc; } #image-list { list-style:none; margin:0; padding:0; } #image-list li { background: #fff; border: 1px solid #ccc; text-align:center; padding:20px; margin-bottom:19px; } #image-list li img { width: 258px; vertical-align: middle; border:1px solid #474747; }
No shockers here, we're just creating some basic styling for our upload form.
Step 2: The PHP
We need to be able to handle the file uploads on the back end as well, so let’s cover that next.
upload.php
<?php foreach ($_FILES["images"]["error"] as $key => $error) { if ($error == UPLOAD_ERR_OK) { $name = $_FILES["images"]["name"][$key]; move_uploaded_file( $_FILES["images"]["tmp_name"][$key], "uploads/" . $_FILES['images']['name'][$key]); } } echo "<h2>Successfully Uploaded Images</h2>";
Bear in mind that these were the first lines of PHP I’d written in easily a year. You should probably be doing a bit more for security; however, we’re simply making sure that there are no upload errors. If that’s the case, we use the built-in move_uploaded_file
to move it to an uploads
folder. Don’t forget to make sure that the folder is writable.
So, right now, we should have a working upload form. You choose an image (multiple, if you want to and your browser lets you), click the Upload Files! button, and you get the message Successfully Uploaded Images.
Here’s what our mini-project looks like so far:
But, come on, it’s 2020: we want more than that. You’ll notice that we’ve linked up jQuery and an upload.js file. Let’s crack that open now.
Step 3: The JavaScript
Let’s dive right into the JavaScript code for file uploading!
(function () { var input = document.getElementById("images"), formdata = false; if (window.FormData) { formdata = new FormData(); document.getElementById("btn").style.display = "none"; } }();
Here’s what we start with. We create two variables: input
is our file input element, formdata
will be used to send the images to the server if the browser supports that. We initialize it to false
and then check to see if the browser supports FormData
. If it does, we create a new FormData
object. Also, if we can submit the images with AJAX, we don’t need the Upload Images! button, so we can hide it. Why don’t we need it? Well, we’re going to auto-magically upload the images immediately after the user selects them.
The rest of the JavaScript will go inside your anonymous self-invoking function. We next create a little helper function that will show the images once the browser has them:
function showUploadedItem (source) { var list = document.getElementById("image-list"), li = document.createElement("li"), img = document.createElement("img"); img.src = source; li.appendChild(img); list.appendChild(li); }
The function takes one parameter: the image source (we’ll see how we get that soon). Then, we simply find the list in our markup and create a list item and image. We set the image source to the source we received, put the image in the list item, and put the list item in the list. Voila!
Next, we have to actually take the images, display them, and upload them. As we’ve said, we’ll do this when the onchange
event is fired on the input element.
if (input.addEventListener) { input.addEventListener("change", function (evt) { var i = 0, len = this.files.length, img, reader, file; document.getElementById("response").innerHTML = "Uploading . . ." for ( ; i < len; i++ ) { file = this.files[i]; if (!!file.type.match(/image.*/)) { } } }, false); }
So, what do we want to do when the user has selected files? First, we create a few variables. The only important one right now is len = this.files.length
. The files that the user has selected will be accessible from the object this.files
. Right now, we’re only concerned with the length
property, so we can loop over the files... and that is exactly what we’re doing next. Inside our loop, we set the current file to file
for ease of access. Next thing we do is confirm that the file is an image. We can do this by comparing the type
property with a regular expression. We’re looking for a type that starts with “image” and is followed by anything. (The double-bang in front just converts the result to a boolean.)
So, what do we do if we have an image on our hands?
if ( window.FileReader ) { reader = new FileReader(); reader.onloadend = function (e) { showUploadedItem(e.target.result); }; reader.readAsDataURL(file); } if (formdata) { formdata.append("images[]", file); }
We check to see if the browser supports creating FileReader
objects. If it does, we’ll create one.
Here’s how we use a FileReader
object: We’re going to pass our file
object to the reader.readAsDataURL
method. This creates a data URL for the uploaded image. It doesn’t work the way you might expect, though. The data url isn’t passed back from the function. Instead, the data url will be part of an event object.
With that in mind, we'll need to register a function on the reader.onloadend
event. This function takes an event object, by which we get the data URL: it’s at e.target.result
. We’re just going to pass this data RUL to our showUploadedItem
function (which we wrote above).
Next, we check for the formdata
object. Remember, if the browser supports FormData
, formdata
will be a FormData
object; otherwise, it will be false
. So, if we have a FormData
object, we’re going to call the append
method. The purpose of a FormData
object is to hold values that you’re submitting via a form; so, the append
method simply takes a key and a value. In our case, our key is images[]
. By adding the square-brackets to the end, we make sure each time we append
another value, we’re actually appending it to that array, instead of overwriting the image
property.
We’re almost done. In our for loop, we’ve displayed each of the images for the user and added them to the formdata
object. Now, we just need to upload the images. Outside the for
loop, here’s the last piece of our puzzle:
if (formdata) { $.ajax({ url: "upload.php", type: "POST", data: formdata, processData: false, contentType: false, success: function (res) { document.getElementById("response").innerHTML = res; } }); }
Again, we have to make sure we have FormData
support; if we don’t, the Upload Files! button will be visible, and that’s how the user will upload the photos. However, if we have FormData
support, we’ll take care of uploading via AJAX. We’re using jQuery to handle all the oddities of AJAX across browsers.
You’re probably familiar with jQuery’s $.ajax
method: you pass it an options object. The url
, type
, and success
properties should be obvious. The data
property is our formdata
object. Notice those processData
and contentType
properties. According to jQuery’s documentation, processData
is true
by default, and will process and transform the data into a query string. We don’t want to do that, so we set this to false
. We’re also setting contentType
to false
to make sure that data gets to the server as we expect it to.
And that’s it. Now, when the user loads the page, they see this:
And after they select the images, they’ll see this:
And the images have been uploaded:
So that's how you can upload files using the vanilla JavaScript. In the next section, we'll see how to implement file upload with the DropzoneJS library.
How to Use the DropzoneJS Library
The DropzoneJS library is a popular free library which allows you to implement the file uploads functionality the blink of an eye. It also supports drag-and-drop file uploads along with a beautiful preview feature.
Let's have a look at the following code which implements the file upload functionality with DropzoneJS.
<!DOCTYPE html> <html> <head> <script src="./dropzone.js"></script> <link rel="stylesheet" href="./dropzone.css"> </head> <body> <form action="/upload.php" class="dropzone"> <div class="fallback"> <input name="images" type="file" multiple /> </div> </form> </body>
You'll have to download the dropzone.js and dropzone.css files locally first.
Apart from that, you just need to use the dropzone
class in the form tag, and the DropzoneJS library will handle the rest!
Let's see how it looks like when you load it in your browser.
As you can see, there's a section which allows you to drop files on it, alternatively you could also select files from your computer by using the default file selection dialog box. Go ahead and drop a few image files on it and it should present you a nice preview as shown in the following screenshot.
Isn't that look amazing with just a few lines of code? In fact, the DropzoneJS library also allows you to customize the UI and other stuff. I would encourage you to check the configuration options provided by this library.
Apart from this, there's the filepond library which is also a popular file upload library you could use. It provides all niche features like drag and drop, progress bar, previews, reordering and alike.
That’s a Wrap!
Uploading files via AJAX is pretty cool, and it’s great that these new technologies support that without the need for lengthy hacks.
Learn JavaScript With a Free Course
If you want to master JavaScript, be sure to check out our free course to learn the complete A-Z of modern JavaScript fundamentals.
In this course, you'll learn all of the essential concepts of the JavaScript language. That's right: all of them! Including the most important recent improvements to the language, in JavaScript ES6 (ECMAScript 2015) and JavaScript ES7 (ECMAScript 2016).
You'll start with the very fundamentals of the language: variables and datatypes. Then in each lesson you'll build knowledge, from data structures like arrays and maps to loops, control structures, and functions. Along with the basics of the language, you'll also learn some key built-in APIs for manipulating data, AJAX, and working with the web browser DOM. Finally, you'll get a look at some of the most powerful and widely used web APIs that are supported by all modern browsers.
This post has been updated with contributions from Sajal Soni. Sajal belongs to India and he loves to spend time creating websites based on open source frameworks.