0

This and this answer is my motivation for trying to convert an object to file type and append to FormData as so:

  var fileBag = new FormData(); 
  fileArray.forEach(function(element) {        
        file_name = element.name;
        file_type = element.type;       
        var file = new File([element], file_name, {type:file_type}); 
        console.log("file type= ", typeof file);    // o/p is object
        fileBag.append(file_name, file);
  });

When I tried the same, typeof newly created file is object (I expect it to be file) after being converted to file. File object is same before and after conversion as so:

File
lastModified: 1543472205025
lastModifiedDate: Thu Nov 29 2018 11:46:45 GMT+0530 (India Standard Time) {}
name: "testFile.xlsx"
size: 1119910
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
webkitRelativePath: ""
__proto__: File

This is how I am sending via Ajax

$.ajax({
    url: '/project/url/', 
    type: 'POST',    
    data: {'file': fileBag},
    enctype: 'multipart/form-data',
    processData: false,
    contentType: false,
    dataType: "json",
    success: function (data) { 
        console.log("data= ",data);

    },
    error: (error) => {
        console.log(JSON.stringify(error));
    }

}); 

I have tried this in both Django and PHP. I am getting empty arrays. My question is:

1) Will the typeof before and after conversion will be the same?

2) How can I send file object arrays to backend? Is there any other solution?

Here is my codepen of the same.

Edit: Codepen code

var fileArray = [];
var fileBag = new FormData();

function handleFileUpload(event)
{
  var fileUploadButtonId = event.currentTarget.id;
  var files = document.getElementById(fileUploadButtonId).files;
  var fileBag = new FormData(); 
  var arrayOfAllUploadedFiles = Array.from(files);

  for(var i=0; i<arrayOfAllUploadedFiles.length; i++)
  {
    fileArray.push(arrayOfAllUploadedFiles[i]);
  }


  fileArray.forEach(function(element) {        
        file_name = element.name;
        file_type = element.type;       
        var file = new File([element], file_name, {type:file_type}); 
        console.log("file type= ", typeof file);    // o/p is object.  // o/p is object. Shouldn't this be 'file'?
        fileBag.append(file_name, file);
        alert("filebag= ",fileBag);  // this is empty
  });
}
Jagruti
  • 275
  • 3
  • 13

1 Answers1

2

Will the typeof before and after conversion will be the same?

Because "file" isn't a JavaScript data type. Everything that isn't a primitive is an object.

console.log(typeof 1);
console.log(typeof "1");
console.log(typeof null);
console.log(typeof undefined);
console.log(typeof [1,2,3]);
console.log(typeof {hello: "world"});
console.log(typeof new Date());
console.log(typeof document.body);
console.log(typeof window);

2) How can I send file object arrays to backend? Is there any other solution?

  1. Understand how data is formatted when you send it over HTTP
  2. Understand the limitations of jQuery

You can't send an array. You can only send some text which server-side code can assemble into an array.

For both standard encodings supported by forms, PHP will populate $_POST with the data in them.

If the name of a field in that data ends in [], PHP will put an array in $_POST.

If you pass an array to jQuery ajax:

data: { someValue: [1, 2, 3] }

Then jQuery will encode it as:

someValue[]=1&someValue[]=2&someValue[]=3

… so PHP will generate an array.

However, the values have to be things that jQuery understands. It can't handle FormData objects.

If you want to send a FormData object (which you have to do in order to send files) then you need to send it instead of an object:

jQuery.ajax({
    url: "/foo",
    data: a_form_data_object,
    processData: false,
    contentType: false,
});

You need processData so it doesn't try to convert the FormData object (i.e. so it will let XMLHttpRequest do that). You need contentType to stop it overriding the one XMLHttpRequest will generate from the FormData object.

So then to send an array, we go back to the rules I described above. You said:

fileBag.append(file_name, file);

But to get an array you need a name ending in [].

fileBag.append("myname[]", file);

Finally, not visible in your question, but looking at your codepen. This will give you a set of files:

document.getElementById(fileUploadButtonId).files;

Since they are files, using code to convert them to files makes no sense.

You can simplify your code:

var fileBag = new FormData(); 
var files = document.getElementById(fileUploadButtonId).files;
var arrayOfAllUploadedFiles = Array.from(files);
fileArray.forEach(file => fileBag.append("myname[]", file);
jQuery.ajax({
    url: "/foo",
    data: fileBag,
    processData: false,
    contentType: false,
});
Quentin
  • 800,325
  • 104
  • 1,079
  • 1,205