3

I'm uploading files via an input type="file" and an XHR request. Uploads proceed very well. The problem is, I can't update my progress bars with onprogress. It works well if I upload only one file, but since there's more than one, there is only one progress bar being updated, the others simply just don"t work. It might come from the for loop, but I don't see how I may fix this If anyone has an idea, that'd be great !

Here's the code:

$('input').change(function() {

var allowedTypes = ['png', 'jpg', 'jpeg', 'gif'];   
var filesLen = this.files.length;
var fileInput = document.querySelector('#file');

for (i = 0; i < filesLen; i++)
{
    var vidType = this.files[i].name.split('.');

    if (allowedTypes.indexOf(vidType[vidType.length -1].toLowerCase()) != -1)
    {
        var progress = 'progress' + i;

        $('input').before('<p>' + this.files[i].name + ' <progress id="' + progress + '"></progress></p>');

        var xhr = new XMLHttpRequest();

        xhr.open('POST', '/upload/');

        xhr.upload.onprogress = function(e) 
        {
            $('#' + progress).attr('value', e.loaded);
        $('#' + progress).attr('max', e.total);
        };

        xhr.onload = function()
        {
            console.log('upload complete');
        };

        var form = new FormData();
        form.append('title', this.files[i].name);
        form.append('pict', fileInput.files[i]);

        xhr.send(form);

    }

    else
    {
        alert('Your file "' + this.files[i].name + '" \'s format isn\'t supported');    
    }
}
1

1 Answer 1

8

This is the "infamous loop problem."

The problem is here:

xhr.upload.onprogress = function(e) 
{
    $('#' + progress).attr('value', e.loaded);
    $('#' + progress).attr('max', e.total);
};

When this function runs, progress will be whatever it was when the loop exited, not what it was at the point in the loop where the function was defined. Try replacing that code with something like this:

(function(progress) { 
    xhr.upload.onprogress = function(e) 
    {
        $('#' + progress).attr('value', e.loaded);
        $('#' + progress).attr('max', e.total);
    };
}(progress));

More: Javascript infamous Loop issue?

Sign up to request clarification or add additional context in comments.

1 Comment

It works, thank you so much ! I'm quite new to JS and i had never heard of this "infamous loop problem". Now after a quick research, i have weel understood the issue : "JavaScript's scopes are function-level, not block-level, and creating a closure just means that the enclosing scope gets added to the lexical environment of the enclosed function." That's why an anonymous function gets rid of this infamous loop problem. Thank you again, you've just released me from a big headache !

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.