1

I am sending data via fetch to the server with FormData(), both JSON data and files. I receive a JSON object with the files, and I update with FormData.append() like this.

var data = {
    title: 'A title',
    img: 'https://fakeimg.pl/500x500/',
    description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
};

let formData = new FormData();
for (var key in data) {
    formData.append(key, data[key]);
}

This works, but only in the first level of the JSON object. And I need to send arrays of data inside my object, which can have files (I will represent the files with {...}):

var data = {
        title: 'A title',
        img: 'https://fakeimg.pl/500x500/',
        description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
        images: [
            { img: 'https://fakeimg.pl/500x500/', imgFile1: {...} },
            { img: 'https://fakeimg.pl/500x500/', imgFile2: {...}  },
            { img: 'https://fakeimg.pl/500x500/', imgFile3: {...}  },
            { img: 'https://fakeimg.pl/500x500/', imgFile4: {...}  },
        ],
    };

I wrote this function:

function iterateObject(object) {
    for (var key in object) {

        if (Array.isArray(object[key])) {
            object[key].map((item) => {
                iterateObject(item);
            });
        } else if (typeof object[key] === 'object') {
            iterateObject(object[key]);
        } else {
            formData.append(key, object[key]);
        }
    }
}
iterateObject(data);

But in the server I end up with:

{
    title: 'A title',
    img: [
        'https://fakeimg.pl/500x500/',
        'https://fakeimg.pl/500x500/',
        'https://fakeimg.pl/500x500/',
        'https://fakeimg.pl/500x500/',
        'https://fakeimg.pl/500x500/',
    ],
    description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
    images: '[object Object],[object Object],[object Object],[object Object]',
};

Does anyone know how to update this object properly, no matter the amount of nesting?

Krisztián Balla
  • 19,223
  • 13
  • 68
  • 84
  • A FormData object stores key/value pairs representing form fields and their values (string or blob). So it is not suitable for passing JSON objects (the images property in your example). What is your desired result? – Krisztián Balla Jul 21 '18 at 15:22
  • 1
    There is a logical error in your `iterateObject` function. The call to `formData.append(key, object[key]);` should be in an `else` after the `if` and the `else if`. – Krisztián Balla Jul 21 '18 at 15:24
  • Thanks Jenny, I'll update it! –  Jul 21 '18 at 15:31
  • By the way, the desired result is to get a formData fill with the data. I suppose that a library like [object-to-formdata](https://www.npmjs.com/package/object-to-formdata) will be convenient here. –  Jul 21 '18 at 15:33
  • 2
    Why not stringify it all to valid JSON, send it to the server under a single key, and then Parse the JSON on the server to recreate the desired object? BTW: `Array.map()` returns an `Array`, so you need to catch it with a variable and pass that into the `FormData` Object. – Brian Peacock Jul 21 '18 at 15:36
  • Hi @BrianPeacock, because I'm using `FormData` and I'm uploading files, so I can't stringify the data (I think). –  Jul 21 '18 at 15:39
  • In your example you are not uploading any files. You have URLs. – Krisztián Balla Jul 21 '18 at 15:41
  • Sorry, I will edit the question, because this is an important requirement! –  Jul 21 '18 at 15:41

1 Answers1

3

One way to achieve this is to use JSON.stringify and send the data Object as the string value of a single key...

  var data = {
    title: 'A title',
    img: 'https://fakeimg.pl/500x500/',
    description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
    images: [
        { img: 'https://fakeimg.pl/500x500/' },
        { img: 'https://fakeimg.pl/500x500/' },
        { img: 'https://fakeimg.pl/500x500/' },
        { img: 'https://fakeimg.pl/500x500/' }
    ]
};

let formData = new FormData();
formData.append("json_data", "'" + JSON.stringify(data) + "'");

... you can then identify your incoming information on the server with the "json_data" key and parse it upon arrival.

Brian Peacock
  • 1,801
  • 16
  • 24
  • 1
    Hi @brianpeacock, is it possible to stringify the files? –  Jul 21 '18 at 15:47
  • @Nikita: What files? – Krisztián Balla Jul 21 '18 at 15:48
  • Sorry, I'm uploading files, and I didn't mention that. Is an important requirement though… –  Jul 21 '18 at 15:50
  • @Nikita: I get that. But there are still no files anywhere in your example. You have URLs. – Krisztián Balla Jul 21 '18 at 15:51
  • Yep, didn't added them to the example, didn't know how to represent them… Maybe with `imgFile: {}`? –  Jul 21 '18 at 15:54
  • See the answers to [this question](https://stackoverflow.com/Questions/5587973/javascript-upload-file) for more on uploading files. – Brian Peacock Jul 21 '18 at 15:54
  • Thanks! I can upload files, is working nicely… the problem is that my object can have files at any level of nesting, and I would like to update all fields with them. –  Jul 21 '18 at 15:56
  • @Nikita: What is inside of `imgFile`? The `{}` indicates a JavaScript object. – Krisztián Balla Jul 21 '18 at 16:01
  • I'm trying to represent the file I'm sending. I suppose it is an object, but I can't inspect it for some reason. Anyway, there is no way to stringify a file, so I can not include it in the example, right? –  Jul 21 '18 at 16:14
  • @Nikita: OK, so it is probably some sort of BLOB. That could be added to a FormData, but not as a nested property, because FormData only supports key/value pairs and no object constructs. – Krisztián Balla Jul 21 '18 at 16:20