1

I am trying to post javascript array of object in an ajax call but i get string value "[]". When i try to console.log the array lenght it says zero.

Following is the code i am using

var masterFileArray = [];  // where I will store the contents
function readMultipleFiles(evt) {
//Retrieve all the files from the FileList object
var files = evt.target.files;
if (files) {
    for (var i = 0, f; f = files[i]; i++) {
        var r = new FileReader();
        r.onload = (function (f) {
            return function (e) {
                var contents = e.target.result;
                masterFileArray.push({name:f.name, contents: contents, type:f.type, size:f.size}); // storing as object

            };
        })(f);
        r.readAsText(f);
    }
    console.log(masterFileArray);
    new Ajax.Request('fileupload.php', {
    method: 'post',
    parameters: {files: JSON.stringify(masterFileArray)},
    onSuccess: function(transport){
        var response = transport.responseText;
        console.log(response);
    }
});

} else {
    alert('Failed to load files');
   }
}
 document.getElementById('upfiles').addEventListener('change', readMultipleFiles, false);

Thats how it looks like on inspection

enter image description here

What i am doing wrong? Any help would be appreciated, Thank you.

7
  • 2
    Because you're adding the elements asynchronously in the onload function, basically. readAsText doesn't block and wait for the file to be read, so your code just proceeds immediately to making the request before the array is populated. Commented Oct 19, 2017 at 15:56
  • You're doing the Ajax Request BEFORE your files have been read by the file reader. Commented Oct 19, 2017 at 15:56
  • 1
    Is r.onload being fired? Console.log inside it to know that :) Commented Oct 19, 2017 at 15:59
  • 1
    Probably read this question and its answers: stackoverflow.com/questions/34495796/… Commented Oct 19, 2017 at 16:01
  • @RômuloM.Farias Yeah it fires. I tested with two images got two logs. Commented Oct 19, 2017 at 16:02

2 Answers 2

1

You can post after reading finished, Here introduced left_loaded_count to get the status of reading. Try like this.

var masterFileArray = [];  // where I will store the contents
var left_loaded_count = 0;
function readMultipleFiles(evt) {
//Retrieve all the files from the FileList object
var files = evt.target.files;
if (files) {
    for (var i = 0, f; f = files[i]; i++) {
        var r = new FileReader();
        r.onload = (function (f) {
            return function (e) {
                var contents = e.target.result;
                masterFileArray.push({name:f.name, contents: contents, type:f.type, size:f.size}); // storing as object
                left_loaded_count -= 1;
                if(left_loaded_count == 0)
                {
                 console.log(masterFileArray);
                 new Ajax.Request('fileupload.php', {
                  method: 'post',
                  parameters: {files: JSON.stringify(masterFileArray)},
                  onSuccess: function(transport){
                     var response = transport.responseText;
                     console.log(response);
                   }
                  });
                }
            };
        })(f);
        left_loaded_count += 1;
        r.readAsText(f);
    }    
} else {
    alert('Failed to load files');
   }
}
 document.getElementById('upfiles').addEventListener('change', readMultipleFiles, false);
Sign up to request clarification or add additional context in comments.

Comments

1

readAsText() is an asynchronous operation, but you proceed with the AJAX call right away instead of waiting for the read operations to finish. That's why your console.log(masterFileArray) prints an empty array, when it runs none of the operations have finished and the array is still empty.

The best way to solve this is to wrap each file read operation in a promise and then proceed with the AJAX call once all these promises resolve.
Get rid of var masterFileArray = [] and change your code within the if (files) { ... } block to this:

  Promise.all(files.map(function(f) {
    return new Promise(function(resolve) {
      var r = new FileReader();
      r.onload = function (e) {
        var contents = e.target.result;
        resolve({name:f.name, contents: contents, type:f.type, size:f.size}); // resolve promise with object
      };
      r.readAsText(f);
    });
  })).then(function(masterFileArray) {
    // All promises have resolved and their results have been collected in masterFileArray
    console.log(masterFileArray);
    new Ajax.Request('fileupload.php', {
      method: 'post',
      parameters: {files: JSON.stringify(masterFileArray)},
      onSuccess: function(transport){
        var response = transport.responseText;
        console.log(response);
      }
    );
  });

Comments

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.