0

For some reason when elements are pushed to an array in the FileReader.onload event function, the elements of that array are later inaccessible. Consider the following code:

scope.targets = [];

for(var i = 0; i < files.length; i++){
        var reader = new FileReader();
        reader.readAsDataURL(files[i]);

        reader.onload = function(e){
              scope.targets.push(e.target.result);
        };
 }

 console.log(scope.targets);
 console.log(scope.targets[0]);

This is the result of the console.log() outputs in Google Chrome Browser. As you can see scope.targets reveals that there's an element of type string. However, scope.targets[0] is undefined. Why is this happening? Is there another way to access the element?

enter image description here


**************************UPDATE*************************************


Here's a solution. Thank You Ashwin Balamohan and nnnnn for your answers, it led me to find a solution. I found what I was looking for here How to implement Progress Bar and Callbacks with async nature of the FileReader

The Solution is:

scope.targets = [];

for(var i = 0; i < files.length; i++){
        var reader = new FileReader();
        reader.readAsDataURL(files[i]);

        reader.onload = function(e){
              scope.targets.push(e.target.result);
              if(i == files.length){
                    callback();
              }
        };
 }

 var callback = function(){
     console.log("scope.targets:");
     console.log(scope.targets);
     console.log("scope.targets[0]:");
     console.log(scope.targets[0]);
 }
Community
  • 1
  • 1
  • due to the nature of your request, we can't reproduce this easily. it would be better for you to make a jsFiddle or something we can use to see the problem. – Greg Borbonus Jun 17 '16 at 03:43
  • 1
    The array is populated within a function that runs asynchronsously and the `console.log()` statements run before that happens. Depending on the browser that you are using, the console may keep a reference to an object that is logged such that by the time you expand the array in the console it does have values in it even though it was empty when logged. Try saying `console.log(JSON.stringify(scope.targets))` at that same point and see what happens. – nnnnnn Jun 17 '16 at 03:45

2 Answers2

0

Can you try this one

scope.targets = {};

for(var i = 0; i < files.length; i++){
        var reader = new FileReader();
        reader.readAsDataURL(files[i]);

        reader.onload = function(e){
              scope.targets[i] = (e.target.result);
        };
 }

console.log(scope.targets);
console.log(scope.targets[0]);
byteC0de
  • 5,153
  • 5
  • 33
  • 66
0

The code is executing asynchronously. See comments below

scope.targets = [];

for(var i = 0; i < files.length; i++){
        var reader = new FileReader();
        reader.readAsDataURL(files[i]);

        // below is an asynchronous call
        reader.onload = function(e){
              scope.targets.push(e.target.result);
        };
 }

 // the asynchronous calls above may or may not be complete by the time you get here
 console.log(scope.targets);
 console.log(scope.targets[0]);

What you can do is to modify your reader.onload function so that it performs the console.log in the callback:

scope.targets = [];

for(var i = 0; i < files.length; i++){
        var reader = new FileReader();
        reader.readAsDataURL(files[i]);

        // below is an asynchronous call
        reader.onload = function(e){
              scope.targets.push(e.target.result);
              // log out the array here, instead
              console.log(scope.targets);
        };
 }
Ashwin Balamohan
  • 3,303
  • 2
  • 25
  • 47
  • Yes, putting the console.log(scope.targets) in the reader.onload function works. However, I need the scope.targets array data outside of the reader.onload function. –  Jun 17 '16 at 04:19
  • Your answer is correct. I was hoping for a solution though. –  Jun 17 '16 at 04:24
  • Great, @Ellioticus. I glad I was able to help in the end. – Ashwin Balamohan Jun 17 '16 at 13:07