HTML5 Multiple File Upload with Progress Bar
Written by Claire Sosset in Labs on 16/05/11
As many developers, the team Centurion love playing and experimenting new technologies.
The new Javascript APIs that revolve around HTML5 are a really fun sandbox for us.
Moreover, experimentation allows us to imagine and realise some new features for Centurion.
By developing this drag and drop uploader, we wanted to provide an easier way for the users to add multiple files in the backoffice of Centurion, and more particularly the contribution of images, like Gmail docs. For the curious folks, here's how it works.
This multiple file upload uses 3 Javascript APIs : Drag and Drop, File, and XmlHttpRequest (XHR).
In the first time we want to pass the files from the desktop to the browser. To do that, I use Drag
and Drop API. This API provides us some events such as « dragstart », « dragenter », « dragleave », « dragover », « drop »... In our case, we will particularly focus on the "drop" event and the DataTransfer object which will allow us to fetch the files datas.
elem.addEventListener('drop', function(e){ handleDrop(e) }, false);
function handleDrop (e){
e.preventDefault();
var files = e.dataTransfer.files;
return false;
};
Remy Sharp has written an interesting article named Native Drag and Drop.
Once the files are fetched, we have to read the datas to extract some informations such as the file name, the file size, and the preview image. For that we use the File API. That provides us the FileReader object. This object has 4 methods to read the file : "readAsArrayBuffer", "readAsBinaryString", "readAsText" and "readAsDataURL".
I have used the "readAsDataURL" in order to create the file preview.
var reader = new FileReader(),
dataUrl = reader.readAsDataURL(file);
reader.onloadend = function(e){
var result = e.target.result;
if (result !== null ) {
var previewWrap = document.createElement('div');
previewWrap.setAttribute('class', 'file-preview');
var imgPreview = document.createElement('img');
imgPreview.setAttribute('src', result);
imgPreview.setAttribute('alt', '');
previewWrap.appendChild(imgPreview);
//insert previewWrap in the DOM
}
};
At this step, we have fetched and read the file. We now want to send all the data to the server.
XHR gives us the ability to request the server without reloading the entire page. The new version of the API lets you make a post request, with the FormData interface, that can send data as a form would have done it. « FormData objects provide a way to easily construct a set of key/value pairs representing form fields and their values, which can then be easily sent using the XMLHttpRequest send() method » (MDN DOC)
this.xhr.open("POST", "url");
var datas = new FormData();
datas.append('Filedata', file);
this.xhr.send(datas);
It's the shorter way i know. But version older than Firefox 4 do not implement the FormData
interface. To solve this probleme, we can use the sendAsBinary method but be careful, this
method is not standard. For more explanations, i invite you to read Paul Rouget's article: uploading files with xmlhttprequest
XHR allow us follow the progress upload. We can create a progress bar like this :
this.xhr = new XMLHttpRequest();
if ( this.xhr ){
this.xhr.upload.addEventListener("progress", function(e){ updateProgress(e) }, false);
function updateProgress(){
if (e.lengthComputable) {
var currentState = (e.loaded / e.total) * 100;
//...
}
}
Other events are also available like « load » and « abort ».
I have tested this demo with chrome 10 and 11, safari 5.0.5, firefox 4 and firefox 3.6.
In Safari, the preview file can't be created because it doesn't support File API.
Below, a list of interesting article that i've found during the development:
- How Gmail’s drag and drop works and why it’s not supported in Safari
- File drag and drop in Firefox 3.6 by Paul Rouget
- Great slides with some compatibility issues
Feedbacks are welcome !
Tags: Javascript , html5 , Drag and Drop , File API
4 comments
By Ana
Can you put a download link to download all the files on this? Thanks
By necmi
Please also state something about the php file. What it should look like?
By claire
Hello,
we have used move_uploaded_file().
You can get the files with the key of FormData ( in our case "Filedata").
For exemple :
$field = 'Filedata';
if(isset($_FILES[$field])){
//move_uploaded_file($_FILES[$field]['tmp_name'], $your_destination)
}
By Nom nom nom
How are you moving the uploaded file in '/demo-multiupload.php'?
I've tried using a move_uploaded_file but that doesn't seem to work.
Add a comment