Node.js

Node.js File Upload with Progress Bar Example

In this post we will look at how to upload files using Node.js and show the user a progress bar with the status of the operation. Node.js, as you know, is a Server side JavaScript framework which has shot to prominence recently. A lot of people with existing skills in JavaScript are now able to use the same for server side logic. We now have the option to build the server side and client side artifacts using the same language, JavaScript.

1. Tools & Technologies

I have used the following toolset to build the example in this post.

  1. Node.js v6.3.0
  2. Formidable Module v1.1.1
  3. Visual Studio Code IDE

You can navigate to the tools page to get them by clicking on the hyperlinks above. Although I have used Visual Studio Code IDE you can switch to other tools that you are comfortable with. Node.js is the server side JavaScript development framework. The formidable module is an additional dependency required for this demo since the native Node.js modules lack certain capabilities we will need to implement this example, notably processing HTML forms posted from the client side.

2. Project Layout

We follow the below folder structure in the example we will build. This is what the final application layout would look like:

Project Layout
index.jsThis file hosts all of our server side logic and exposes the API we use for Uploading.
file.uploader.jsThis file contains the client side logic and is referenced in our index.html landing page.
index.htmlIt is our landing page with all our HTML markup to build a file uploader.
file.uploader.cssOur styles reside in this css file.

3. Server side Implementation

The server side implementation resides in the file index.js. In this file we create a web server using the http module that comes with Node itself. But there is no way to handle or process incoming HTML forms which are POSTed to the server. So we leverage a module called formidable. This module allows us to parse the incoming form and access the form data from the request object. The http module provides us both the request and response object. Files uploaded using POST requests get saved to a temporary location on the server. We then access these files and move them to a folder on our server. Let us see what our code looks like followed by explanation of the same.

index.js

var http = require("http");
var url = require("url");
var fs = require("fs");
var formidable = require("formidable");
var port = 8090;
var host = "localhost";

http.createServer(function (req, res) {
    var path = url.parse(req.url, true);
    if(path.pathname.endsWith("html")){
        fs.readFile("." + path.pathname, function(err, data){
            res.writeHead(200, "ok", { "Content-Type": "text/html"});
            res.write(data);
            res.end();
        });
    } else if(path.pathname.endsWith("js")){
        fs.readFile("." + path.pathname, function(err, data){
            res.writeHead(200, "ok", { "Content-Type": "text/javascript"});
            res.write(data);
            res.end();
        });
    } else if(path.pathname.endsWith("css")){
        fs.readFile("." + path.pathname, function(err, data){
            res.writeHead(200, "ok", {"Content-Type": "text/css"});
            res.write(data);
            res.end();
        });
    } else if(path.pathname.endsWith("uploadFile")){
        var form = new formidable.IncomingForm();
        form.parse(req, function(err, fields, files){
            var oldpath = files.file.path;
            var newpath = 'C:/Users/siddharth/' + files.file.name;
            fs.rename(oldpath, newpath, function (err) {
              if (err) throw err;
              res.write('File uploaded and moved!');
              res.end();
            });
            
        });
       
    }

}).listen(port, host);

As you can see in the code above we implement a web server using http module. Firstly we parse the URL using the url module. We check if the incoming request is for a resource file. In case the request is for a html, js, css file we return the same to the browser. But if the request is for uploadFile URL then we proceed to process the posted files. We hand over the request object provided by http module to the formidable module’s IncomingForm object using its parse method. It returns us, among other things, a list of files uploaded to our callback function. We then move the files from their temporary location to a folder in the Users directory. Afterwards we return an OK response to the browser.

4. Client side Implementation

On the client end we will use an input tag with type attribute as file and decorat it with multiple attribute. This tag will be hidden though and we will trigger it’s click when we need to show the Open File Dialog. Later we will listen to its change to get the list of selected files to upload. We will use a button on the UI for the user to use the feature. Once we have the list of files to upload we will initialize our progress bar and update it on the progress event of the XMLHttpRequest object’s upload property. We will use AJAX to post the files to the server side. The progress event handler is called with data like the total number of bytes and number of bytes uploaded. The progress bar is actually two divs one inside the other. The inner div has a background color of green and a width of 0%. As the upload progresses we increase the width of the inner div to show progress of the upload. The code for all this resides in the file.uploader.js file and looks like below:

file.uploader.js

var browse = document.getElementsByClassName('selectFiles')[0];
var fileDialog = document.createElement("INPUT");
fileDialog.setAttribute("type", "file");
fileDialog.setAttribute("multiple", "true");
fileDialog.style.display = "none";
var uploadProgress = document.getElementsByClassName("uploadProgressDetails")[0];
var progress;
setupProgressBar();
browse.addEventListener("click", function(){    
    fileDialog.click();
    
});

fileDialog.addEventListener("change", function(){
    
    processFiles(fileDialog.files);

});

function processFiles(files){
    
    resetProgressBar();
    var request = new XMLHttpRequest();       
    request.upload.addEventListener("progress", showProgress);
    request.open("POST", "/uploadFile");
    var formData = new FormData();
    for(var file = 0; file < files.length; file++){         
        
        formData.append("file" + file, files[file], files[file].name);
        
    } 
    request.send(formData);  
}
function showProgress(evt){   
    
    progress.style.width = (((evt.loaded/evt.total)*100))+ "%";

}
function resetProgressBar(){
    progress.style.width = "0%";
}
function setupProgressBar(){
    var progressBar = document.createElement("DIV");
    progressBar.className = "progressBar";
    uploadProgress.appendChild(progressBar);
    var innerDIV = document.createElement("DIV");
    innerDIV.className = "progress";
    progressBar.appendChild(innerDIV);
    progress = document.getElementsByClassName("progress")[0];
}

5. Running the Application

To run the example application we have built you need to run the following commands in order at the root of the application.
First execute

> npm install

then

> node index.js

Now, we can navigate to the URL http://localhost:8090/index.html to test out the File upload functionality we just implemented. The landing page should look like below:

Index.html — Landing Page

On clicking the “Browse” button a File Open Dialog should open. We can select a single file or multiple files using Shift or CTRL keys while making selections. As we click the Open button the upload would begin and we can see the progress bar updating to reflect the progress.

6. Download the Source Code

This wraps up our effort to write an application for Node.js File Uploading with Progress Bar.

Download
You can download the full source code of this example here : WCG — Node.js File Upload with Progress Bar

Siddharth Seth

Siddharth is a Software Development Professional with a Master degree in Computer Applications from IGNOU. He has over 14 years of experience. And currently focused on Software Architecture, Cloud Computing, JavaScript Frameworks for Client and Server, Business Intelligence.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
sehbas82
sehbas82
5 years ago

hello sir,
i got following error

sehbas82
sehbas82
5 years ago

var storage = multer.diskStorage({
^

TypeError: multer.diskStorage is not a function
at Object. (D:\New folder (2)\File-upload-in-Node-master\Server.js:4:22)
at Module._compile (internal/modules/cjs/loader.js:654:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:665:10)
at Module.load (internal/modules/cjs/loader.js:566:32)
at tryModuleLoad (internal/modules/cjs/loader.js:506:12)
at Function.Module._load (internal/modules/cjs/loader.js:498:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:695:10)
at startup (internal/bootstrap/node.js:201:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:516:3)

Back to top button