Question

I´m trying to show a preview and name of images before upload it with ajax. I use the File Read API to show the preview and, at the same time, use the ".name" method to show the file name, the problem is that its show me all the preview but all the images have the same name, the last file name. Thanks!

$('input').change(function(){
    for (var i=0; i<this.files.length; i++){
        var reader = new FileReader()
        reader.onload = function (e) {
            $('ul').append('<li><img src="'+e.target.result+'">'+this.files[i].name+'</li>')
        }
        reader.readAsDataURL(this.files[i]) 
    }

})
Was it helpful?

Solution

Create a new scope (closure) to keep the value of i, as by the time the asynchronous onload handler fires, the loop has finished, and the value of i will be the last one set, passing it to an IIFE solves this

$('input').change(function () {
    for (var i=0, len = this.files.length; i < len; i++) {
        (function (j, self) {
            var reader = new FileReader()
            reader.onload = function (e) {
                $('ul').append('<li><img src="' + e.target.result + '">' + self.files[j].name + '</li>')
            }
            reader.readAsDataURL(self.files[j])
        })(i, this);
    }
});

FIDDLE

OTHER TIPS

In Javascript, a for loop iterator variable is not truly in scope within the for loop.

In this example, variable "i" will still be "5" after the loop has finished running:

arrTest = [1,2,3,4,5];
for (var i=0; i<arrTest.length; i++){
    console.log(i);
}
alert(i);

Because of this quirk, it is a best practice in Javascript to write for loops like this:

var i;
for (i=0; i<arrTest.length; i++){
    console.log(i);
}

So, you're running in to a "race condition" due to the scoping of for loop variables. Can you access the file name through that "e" parameter, instead?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top