0

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]) 
    }

})
lucasmenendez
  • 116
  • 1
  • 11
  • hey I think it's a "race condition" where your loop completes before FileReader has finished loading. Can you access the file name through the e parameter, instead? – BumbleB2na Apr 07 '14 at 22:48

2 Answers2

2

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

adeneo
  • 312,895
  • 29
  • 395
  • 388
-2

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?

BumbleB2na
  • 10,723
  • 6
  • 28
  • 30
  • i try show the name with "e" parameter, but the result is "undefined" – lucasmenendez Apr 07 '14 at 23:03
  • I checked the documentation and that won't work. Refer to this Q&A for help with loading multiple files one-by-one: http://stackoverflow.com/questions/13975031/reading-multiple-files-with-javascript-filereader-api-one-at-a-time - If you read them one at a time, then you will be able to access each file's data, such as "name", within your loop. – BumbleB2na Apr 07 '14 at 23:06
  • Sorry but reading the page that u give me cant understand in which part of recursive function is used the file name. Thanks! – lucasmenendez Apr 07 '14 at 23:33
  • 1
    @LukasKas - This isn't even close to what the issue is, declaring the var outside the loop is exactly the same as inside the for statement, and it's not a race condition, it's a scope issue. – adeneo Apr 08 '14 at 00:46
  • @adeneo Your solution is good. I would have resolved it in a different way than you but I should try using closures for once. – BumbleB2na Apr 08 '14 at 14:13