Sending nested FormData on AJAX

kunde picture kunde · Feb 27, 2015 · Viewed 21.9k times · Source

I need to send some data using ajax and FormData, because I want to send a file and some other parameters. The way I usually send data is this:

$.ajax({
    type:       'POST',
    url:        'some_url',
    dataType:   'json',
    processData:false,
    contentType:false,
    data:{
        Lvl_1-1: 'something',
        Lvl_1-2: 'something',
        Lvl_1-3: {
            Lvl_1-3-1: "something",
            Lvl_1-3-2: "something",
            Lvl_1-3-3: "something",
        },
    },
    ...
});

If I don't use FormData(), I have no problem, but when using FormData(), only the data on Lvl1 is ok, but anything nested is displayed as string like this

<b>array</b> <i>(size=3)</i>
    'Lvl1-1' <font color='#888a85'>=&gt;</font> <small>string</small> 
        <font color='#cc0000'>'Something'</font> 
        <i>(length=23)</i>
    'Lvl1-2' <font color='#888a85'>=&gt;</font> <small>string</small> 
        <font color='#cc0000'>''Something''</font> <i>(length=3)</i>
    'Lvl1-3' <font color='#888a85'>=&gt;</font> <small>string</small> 
        <font color='#cc0000'>'[object Object]'</font> <i>(length=17)</i>

If I use FormData() to encode the data inside Lvl1-3, instead of [object Object] I get [object FormData]

How do I get an array instead of string on Lvl1-3?

NOTE: If the file is on top level (Lvl_1) I can send the file with no problems using FormData(). I didn't wrote the code of the file attached because that's not the problem, nested data is. I just mentioned the file because that's why I'm using FormData().

Answer

Quentin picture Quentin · Feb 27, 2015

URL Encoded form data doesn't have any native way to express complex data structures. It only supports simple key=value pairs.

?foo=1&bar=2

Most form data parsing libraries allow arrays of data using keys with the same name

?foo=1&foo=2

PHP bolted its own syntax on top of that format:

?foo[]=1&foo[]=2

which allowed for named keys in an associative array:

?foo[bar]=1&foo[baz]=2

and nested arrays:

?foo[bar][level2a]=1&foo[bar][level2b]=2

Due to the prevalence of PHP, jQuery adopted that syntax for generating form data when you pass a JavaScript object to data.

If you want to use FormData then jQuery won't reprocess it for you.

The effect you are seeing is because you are trying to put an object (I'm guessing a FormData instance, but you haven't showed that part of your code) as the second argument to append - where a string is expected.

You need to generate the key names using PHP's syntax yourself.

form_data_instance.append("Lvl_1-3[Lvl_1-3-1]", "something");
form_data_instance.append("Lvl_1-3[Lvl_1-3-2]", "something");
form_data_instance.append("Lvl_1-3[Lvl_1-3-3]", "something");