I'm uploading multiple files via XmlHTTPRequest and HTML5. I have the uploading working fine, but I would like to have a progress bar for each file upload going on. The code I have, however, uses the last progress bar for ALL of the file uploads instead of each upload using its own progress bar. So this is mostly visual on the client-side, but it's really annoying me. For some reason I'm assuming that the event that attaches the progress of the file upload overwrites itself and uses the last progress bar. Here's my code:
var files = event.dataTransfer.files;
// iterate over each file to upload, send a request, and attach progress event
for (var i = 0, file; file = files[i]; i++) {
var li = $("<li>" + file.name + "<div class='progressbar'></div></li>");
// add the LI to the list of uploading files
$("#uploads").append(li);
// fade in the LI instead of just showing it
li.hide().fadeIn();
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', function(e) {
var percent = parseInt(e.loaded / e.total * 100);
li.find(".progressbar").width(percent);
}, false);
// check when the upload is finished
xhr.onreadystatechange = stateChange;
// setup and send the file
xhr.open('POST', '/attachments', true);
xhr.setRequestHeader('X-FILE-NAME', file.name);
xhr.send(file);
}
I'm assuming that the proper "li" is not getting read properly by the "progress" event. I suspect there's some sort of binding I have to do to tell the "progress" event to use a particular variable as it's "li", but I'm not sure what I'm missing.
You could add a new <input type="file"> whenever you finished uploading the previous files and hide the previous input. This way you keep adding a new input every time you want to add more files and prevent the previous input from being overwritten.
Your example doesn't work properly becourse you don't take into account that xhr progress event is fired when all list items had been already created. However there are a lot of ways to make your example work. The idea is to let xhr know what exactly list item it is dealing with. For example use this code (I didn't check if it works. The purpose of this code is to describe the idea):
var xhr = new XMLHttpRequest();
xhr.upload.li = li;
xhr.upload.addEventListener('progress', function(e) {
var percent = parseInt(e.loaded / e.total * 100);
this.li.find(".progressbar").width(percent);
}, false);
I think I found a solution for this problem. It looks working on some of my tests. I'm not very good at english thus I'll just share my sample script. If you ask any question, I'll try to explain more :)
// This is input object which type of file.
var uploader = document.getElementById("fileUploader");
// We'll send a new post for each file.
for(var i=0, j=uploader.files.length; i<j; i++)
{
var uploaderForm = new FormData(); // Create new FormData
uploaderForm.append("action","upload"); // append extra parameters if you wish.
uploaderForm.append("up_file",uploader.files[i]); // append the next file for upload
var xhr = new XMLHttpRequest();
xhr.addEventListener("loadstart", function(e){
// generate unique id for progress bars. This is important because we'll use it on progress event for modifications
this.progressId = "progress_" + Math.floor((Math.random() * 100000));
// append progress elements to somewhere you want
$("body").append('<div id="' + this.progressId + '" class="myCustomProgressBar" ></div>');
});
xhr.addEventListener("progress", function(e){
var total = e.total;
var loaded = e.loaded;
var percent = (100 / total) * loaded; // Calculate percentage of loaded data
// I animate progress object. Notice that i use "this.progressId" which i created on loadstart event.
$("#" + this.progressId).animate({"width":300 * (percent / 100)}, 800);
});
xhr.open("POST","index.php");
xhr.send(uploaderForm);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With