Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HTML5 file uploading with multiple progress bars

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.

like image 958
Dan L Avatar asked Jul 18 '11 04:07

Dan L


People also ask

How do you append files in input type file multiple before uploading?

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.


2 Answers

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);
like image 141
Molecular Man Avatar answered Nov 01 '22 17:11

Molecular Man


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);
}
like image 23
Mehmet Hazar Artuner Avatar answered Nov 01 '22 16:11

Mehmet Hazar Artuner