Uploading files to the server using AJAX

Written Oct 25, 2013

Uploading a file an process it in the backend in one of the most common file handling functionalities in a web app: think about uploading an avatar or an attachment.

There are a lot of pre-built libraries that deal with this, but let's keep things simple by writing the smallest amount of code needed for this task. The solution here provided does not provide progress tracking, which can be implemented upon it.

<input type="file" id="fileUpload" />

var App = {};

App.handleImageUpload = function handleImageUpload(event) {
  var files = event.target.files;
  var myImage = files[0];
  that.sendFile(myImage);
}

$('#fileUpload').addListener('change', function(event) {
  App.handleImageUpload(event)
},

var sendFile = function sendFile(file) {
  var uri = '/saveImage';
  var xhr = new XMLHttpRequest();
  var fd = new FormData();

  xhr.open('POST', uri, true);
  xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) {
      var imageName = xhr.responseText;
      //do what you want with the image name returned
      //e.g update the interface
    }
  };
  fd.append('myFile', file);
  xhr.send(fd);
}

This is the frontend code. We register a change handler on the #fileUpload DOM element, and when the user chooses an image, we trigger the sendFile() function passing in the file selected.

sendFile() prepares the XHR (AJAX) request and sends the file to the server. When the server returns successfully, it will send us the image name. With that, we will do what we need to do, like updating the interface with the image.

The FormData functionality is working in all the modern browsers, as it's part of the XMLHttpRequest 2 spec. Keep in mind that IE versions prior to 10 do not support it.

The server part is detailed here below. I'm using Node.js with the Express framework to handle the request, and the fs module to save the file to disk, in a directory /files/ relative to the path where the source file lives.

var fs = require('fs');

app.post('/saveImage', function (req, res) {
  var fileName = req.files.myFile.name;
  fs.readFile(req.files.myFile.path, function (err, data) {
    var newPath = __dirname + '/images/' + fileName;
    fs.writeFile(newPath, data, function (error) {
      if (error) {
        console.log(error);
        res.end();
      } else {
        res.end(fileName);
        //here you can save the file name to db, if needed
      }
    });
  });
});

This is the smallest amount of code needed to handle files.

If you need to check the filetype or the file size, you can preprocess them in the App.handleImageUpload function, like:

App.handleImageUpload = function handleImageUpload(event) {
  var files = event.target.files;
  var myImage = files[0];

  var imageType = /image.*/;

  if (!myImage.type.match(imageType)) {
    alert('Sorry, only images are allowed');
    return;
  }

  if (myImage.size > (100*1024)) {
    alert('Sorry, the max allowed size for images is 100KB');
    return;
  }

  that.sendFile(myImage);
}

More information about file handling: