59

I'm using FormData to upload files. I also want to send an array of other data.

When I send just the image, it works fine. When I append some text to the formdata, it works fine. When I try to attach the 'tags' array below, everything else works fine but no array is sent.

Any known issues with FormData and appending arrays?

Instantiate formData:

formdata = new FormData();

The array I create. Console.log shows everything working fine.

        // Get the tags
        tags = new Array();
        $('.tag-form').each(function(i){
            article = $(this).find('input[name="article"]').val();
            gender = $(this).find('input[name="gender"]').val();
            brand = $(this).find('input[name="brand"]').val();
            this_tag = new Array();
            this_tag.article = article;
            this_tag.gender = gender;
            this_tag.brand = brand;
            tags.push(this_tag);    
            console.log('This is tags array: ');
            console.log(tags);
        });
        formdata.append('tags', tags);
        console.log('This is formdata: ');
        console.log(formdata);

How I send it:

        // Send to server
        $.ajax({
            url: "../../build/ajaxes/upload-photo.php",
            type: "POST",
            data: formdata,
            processData: false,
            contentType: false,
            success: function (response) {
                console.log(response);
                $.fancybox.close();
            }
        });
Don P
  • 60,113
  • 114
  • 300
  • 432

13 Answers13

86

How about this?

formdata.append('tags', JSON.stringify(tags));

... and, correspondingly, using json_decode on server to deparse it. See, the second value of FormData.append can be...

a Blob, File, or a string, if neither, the value is converted to a string

The way I see it, your tags array contains objects (@Musa is right, btw; making this_tag an Array, then assigning string properties to it makes no sense; use plain object instead), so native conversion (with toString()) won't be enough. JSON'ing should get the info through, though.

As a sidenote, I'd rewrite the property assigning block just into this:

tags.push({article: article, gender: gender, brand: brand});
raina77ow
  • 103,633
  • 15
  • 192
  • 229
  • The only problem is JSON.stringify() gives me the output with escaped quotes. That makes it unable to be interpreted on the PHP side. Do you know how to destringify? – Don P Dec 25 '12 at 04:29
  • Here is the output [{\"article\":\"Article\",\"gender\":\"Gender\",\"brand\":\"Brand\"}] – Don P Dec 25 '12 at 04:29
  • If you are using asp.net with automatic mapping or something similar, then this answer is what you need. http://stackoverflow.com/a/28434829/625581 – Martín Coll Jul 10 '15 at 19:52
  • hi @raina77ow i want to like this send array but server side i am not getting this array object image is getting but array not getting?can you please help me – coderwill Apr 12 '17 at 12:14
  • Shouldn't have to do this. The easy way is append to a key with square brackets. – lookininward May 15 '19 at 18:24
  • if i gave json stringfy means i cant insert that tag table. i use form data in post man – Jenifer K Jul 21 '22 at 10:28
39

Writing as

var formData = new FormData;
var array = ['1', '2'];
for (var i = 0; i < array.length; i++) {
    formData.append('array_php_side[]', array[i]);
}

you can receive just as normal array post/get by php.

Yosuke
  • 411
  • 4
  • 2
20

We can simply do like this.

formData = new FormData;
words = ["apple", "ball", "cat"]
words.forEach((item) => formData.append("words[]", item))

// verify the data
console.log(formData.getAll("words[]"))
//["apple", "ball", "cat"]

On server-side you will get words = ["apple", "ball", "cat"]

rakeshpatra
  • 683
  • 8
  • 24
18

use "xxx[]" as name of the field in formdata (you will get an array of - stringified objects - in you case)

so within your loop

$('.tag-form').each(function(i){
            article = $(this).find('input[name="article"]').val();
            gender = $(this).find('input[name="gender"]').val();
            brand = $(this).find('input[name="brand"]').val();
            this_tag = new Array();
            this_tag.article = article;
            this_tag.gender = gender;
            this_tag.brand = brand;
            //tags.push(this_tag);    
            formdata.append('tags[]', this_tag);
...
halfbit
  • 3,773
  • 2
  • 34
  • 47
  • Brilliant! My needs are similar to the OP's, but I want to fill the `FormData` object with an array of file inputs. I am attempting to upload an arbitrary number of files, with AJAX, which the user specifies with standard form input elements. The server-side implementation requires all of the files to be nested under a single key, and this was the only way I was able to achieve that. There is absolutely no mention of this array-notation technique at https://developer.mozilla.org/en-US/docs/Web/API/FormData/append . I can't thank you enough, halfbit! – Ben Johnson Oct 07 '15 at 12:45
  • I added an example to the above-cited documentation that demonstrates this specific usage. The ability to include the square brackets is hugely useful when dealing with multi-file uploads because the resultant data structure is so much more conducive to looping. Thanks again! – Ben Johnson Oct 07 '15 at 13:38
7

Function:

function appendArray(form_data, values, name){
    if(!values && name)
        form_data.append(name, '');
    else{
        if(typeof values == 'object'){
            for(key in values){
                if(typeof values[key] == 'object')
                    appendArray(form_data, values[key], name + '[' + key + ']');
                else
                    form_data.append(name + '[' + key + ']', values[key]);
            }
        }else
            form_data.append(name, values);
    }

    return form_data;
}

Use:

var form = document.createElement('form');// or document.getElementById('my_form_id');
var formdata = new FormData(form);

appendArray(formdata, {
    sefgusyg: {
        sujyfgsujyfsg: 'srkisgfisfsgsrg',
    },
    test1: 5,
    test2: 6,
    test3: 8,
    test4: 3,
    test5: [
        'sejyfgjy',
        'isdyfgusygf',
    ],
});
agm1984
  • 15,500
  • 6
  • 89
  • 113
Doglas
  • 642
  • 1
  • 11
  • 22
5

This is the way I did it:

const data = new FormData();
data.append('id', class.id);
data.append('name', class.name);

class.people.forEach((person, index) => {
    data.append(`people[${index}].id`, person.id);
    data.append(`people[${index}].firstname`, person.firstname);
    data.append(`people[${index}].lastname`, person.lastname);

    // Append images
    person.images.forEach((image, imageIndex) =>
        data.append(`people[${index}].images`, {
            name: 'image' + imageIndex,
            type: 'image/jpeg',
            uri: image,
        })
    );
});

I am using React on the frontend and Asp.Net on the backend.

Tom el Safadi
  • 6,164
  • 5
  • 49
  • 102
3

Simply you can do like this:

var formData = new FormData();
formData.append('array[key1]', this.array.key1);
formData.append('array[key2]', this.array.key2);
Mobasher Fasihy
  • 1,021
  • 2
  • 9
  • 17
3
var formData = new FormData; var arr = ['item1', 'item2', 'item3'];

arr.forEach(item => {
    formData.append(
        "myFile",item
    ); });
Amey
  • 31
  • 1
2
var formData = new FormData;
var alphaArray = ['A', 'B', 'C','D','E'];
for (var i = 0; i < alphaArray.length; i++) {
    formData.append('listOfAlphabet', alphaArray [i]);
}

And In your request you will get array of alphabets.

Deva
  • 1,851
  • 21
  • 22
  • 1
    Brillant idea, but this works in my code only if brackets `[]` are used: `formData.append('listOfAlphabet[]', alphaArray [i]);`. Otherwise PHP does not get the full array, but only the last item. – Steevie Apr 29 '20 at 08:52
1

You can only stringify the array and append it. Sends the array as an actual Array even if it has only one item.

const array = [ 1, 2 ];
let formData = new FormData();
formData.append("numbers", JSON.stringify(array));
Marko Rochevski
  • 1,184
  • 8
  • 12
1

This works for me when I sent file + text + array:

const uploadData = new FormData();
if (isArray(value)) {
  const k = `${key}[]`;
  uploadData.append(k, value);
} else {
  uploadData.append(key, value);
}


const headers = {
  'Content-Type': 'multipart/form-data',
};
llioor
  • 5,804
  • 4
  • 36
  • 44
0

I'm sending files(array) using formData in vuejs
for me below code is working

        if(this.requiredDocumentForUploads.length > 0) {
            this.requiredDocumentForUploads.forEach(file => {
                var name = file.attachment_type  // attachment_type is using for naming
                if(document.querySelector("[name=" + name + "]").files.length > 0) {
                    formData.append("requiredDocumentForUploadsNew[" + name + "]", document.querySelector("[name=" + name + "]").files[0])
                }
            })
        }
Shreekanth
  • 829
  • 1
  • 9
  • 12
0

Use JSON.stringify at the frontend as below:

...
...
const entityData = new FormData();
entityData.append("Entities Open", JSON.stringify(login_entities));
axios
.post("/oneview/load_entity", entityData)
.then(response => {
   var entity_group = response.data.entity_group;
   var entity_code = response.data.entity_code;
   var entity_name = response.data.entity_name;
})
.catch(error => {
   console.log(error);
   alert(error);
});

Then use json.loads() at the backend as below:

...
...
login_entities = json.loads(request.POST.get('Entities Open'))
for i in login_entities:
   ...
   ...
Fred
  • 211
  • 2
  • 9