How to convert FormData (HTML5 object) to JSON

420.3k Views Asked by At

How do I convert the entries from a HTML5 FormData object to JSON?

The solution should not use jQuery. Also, it should not simply serialize the entire FormData object, but only its key/value entries.

34

There are 34 best solutions below

17
On BEST ANSWER

You could also use forEach on the FormData object directly:

var object = {};
formData.forEach(function(value, key){
    object[key] = value;
});
var json = JSON.stringify(object);

UPDATE:

And for those who prefer the same solution with ES6 arrow functions:

var object = {};
formData.forEach((value, key) => object[key] = value);
var json = JSON.stringify(object);

UPDATE 2:

And for those who want support for multi select lists or other form elements with multiple values (since there are so many comments below the answer regarding this issue I will add a possible solution):

var object = {};
formData.forEach((value, key) => {
    // Reflect.has in favor of: object.hasOwnProperty(key)
    if(!Reflect.has(object, key)){
        object[key] = value;
        return;
    }
    if(!Array.isArray(object[key])){
        object[key] = [object[key]];    
    }
    object[key].push(value);
});
var json = JSON.stringify(object);

Here a Fiddle demonstrating the use of this method with a simple multi select list.

UPDATE 3:

As a side note for those ending up here; in case the purpose of converting the form data to json is to send it through an XMLHttpRequest to a server you can send the FormData object directly without converting it. As simple as this:

var request = new XMLHttpRequest();
request.open('POST', 'http://example.com/submitform.php');
request.send(formData);

See also Using FormData Objects on MDN for reference.

Or alternatively you can do the same with the modern day Fetch API:

fetch('http://example.com/submitform.php', {
  method: 'POST',
  body: formData
}).then((response) => { 
  // do something with response here... 
});

See also Using The Fetch API on MDN for reference.

UPDATE 4:

As mentioned in one of the comments below my answer the JSON stringify method won't work out of the box for all types of objects. For more information on what types are supported I would like to refer to the Description section in the MDN documentation of JSON.stringify.

In the description is also mentioned that:

If the value has a toJSON() method, it's responsible to define what data will be serialized.

This means that you can supply your own toJSON serialization method with logic for serializing your custom objects. Like that you can quickly and easily build serialization support for more complex object trees.

7
On

You can achieve this by using the FormData() object. This FormData object will be populated with the form's current keys/values using the name property of each element for the keys and their submitted value for the values. It will also encode file input content.

Example:

var myForm = document.getElementById('myForm');
myForm.addEventListener('submit', function(event)
{
    event.preventDefault();
    var formData = new FormData(myForm),
        result = {};

    for (var entry of formData.entries())
    {
        result[entry[0]] = entry[1];
    }
    result = JSON.stringify(result)
    console.log(result);

});
0
On
const formData = new FormData();
formData.set('name', "name");
var object = {};
formData.forEach((value, key) => object[key] = value);
var json = object
console.log(json)
0
On

Here's a way that includes a simple way to handle multiple values. If a key ends with [], it combines the values into an array (like in the old php convention), and drops the [] from the key:

function formDataToJson(f) {
  return Object.fromEntries(Array.from(f.keys(), k =>
    k.endsWith('[]') ? [k.slice(0, -2), f.getAll(k)] : [k, f.get(k)]));
}

For example, if you have:

const f = new FormData();
f.append("a", "1");
f.append("a", "2");
f.append("b[]", "3");
f.append("b[]", "4");
formDataToJson(f)  // --> produces {a: "1", b: ["3","4"]}
3
On

This post is already a year old... but, I really, really like the ES6 @dzuc answer. However it is incomplete by not been able to handle multiple selects or checkboxes. This has already pointed and code solutions has been offered. I find them heavy and not optimized. So I wrote a 2 versions based on @dzuc to handle these cases:

  • For ASP style forms where multiple items name could just simple repeated.
let r=Array.from(fd).reduce(
  (o , [k,v]) => (
     (!o[k])
     ? {...o , [k] : v}
     : {...o , [k] : [...o[k] , v]}
   )
   ,{}
);
let obj=JSON.stringify(r);

One line Hotshot version:

Array.from(fd).reduce((o,[k,v])=>((!o[k])?{...o,[k]:v}:{...o,[k]:[...o[k],v]}),{});
  • For PHP style forms where the multiple item names must have a [] suffix.
let r=Array.from(fd).reduce(
  (o , [k,v]) => (
    (k.split('[').length>1)
    ? (k=k.split('[')[0]
      , (!o[k])
      ? {...o , [k] : [v]}
      : {...o , [k] : [...o[k] , v ]}
    )
    : {...o , [k] : v}
  )
  ,{}
);
let obj=JSON.stringify(r);

One line Hotshot version:

Array.from(fd).reduce((o,[k,v])=>((k.split('[').length>1)?(k=k.split('[')[0],(!o[k])?{...o,[k]:[v]}:{...o,[k]:[...o[k],v]}):{...o,[k]:v}),{});
  • Extension of PHP form that support multi-level arrays.

Since last time I wrote the previous second case, at work it came a case that the PHP form has checkboxes on multi-levels. I wrote a new case to support previous case and this one. I created a snippet to better showcase this case, the result show on the console for this demo, modify this to your need. Tried to optimize it the best I could without compromising performance, however, it compromise some human readability. It takes advantage that arrays are objects and variables pointing to arrays are kept as reference. No hotshot for this one, be my guest.

let nosubmit = (e) => {
  e.preventDefault();
  const f = Array.from(new FormData(e.target));
  const obj = f.reduce((o, [k, v]) => {
    let a = v,
      b, i,
      m = k.split('['),
      n = m[0],
      l = m.length;
    if (l > 1) {
      a = b = o[n] || [];
      for (i = 1; i < l; i++) {
        m[i] = (m[i].split(']')[0] || b.length) * 1;
        b = b[m[i]] = ((i + 1) == l) ? v : b[m[i]] || [];
      }
    }
    return { ...o, [n]: a };
  }, {});
  console.log(obj);
}
document.querySelector('#theform').addEventListener('submit', nosubmit, {capture: true});
<h1>Multilevel Form</h1>
<form action="#" method="POST" enctype="multipart/form-data" id="theform">
  <input type="hidden" name="_id" value="93242" />
  <input type="hidden" name="_fid" value="45c0ec96929bc0d39a904ab5c7af70ef" />
  <label>Select:
    <select name="uselect">
      <option value="A">A</option>
      <option value="B">B</option>
      <option value="C">C</option>
    </select>
  </label>
  <br /><br />
  <label>Checkboxes one level:<br/>
    <input name="c1[]" type="checkbox" checked value="1"/>v1 
    <input name="c1[]" type="checkbox" checked value="2"/>v2
    <input name="c1[]" type="checkbox" checked value="3"/>v3
  </label>
  <br /><br />
  <label>Checkboxes two levels:<br/>
    <input name="c2[0][]" type="checkbox" checked value="4"/>0 v4 
    <input name="c2[0][]" type="checkbox" checked value="5"/>0 v5
    <input name="c2[0][]" type="checkbox" checked value="6"/>0 v6
    <br/>
    <input name="c2[1][]" type="checkbox" checked value="7"/>1 v7 
    <input name="c2[1][]" type="checkbox" checked value="8"/>1 v8
    <input name="c2[1][]" type="checkbox" checked value="9"/>1 v9
  </label>
  <br /><br />
  <label>Radios:
    <input type="radio" name="uradio" value="yes">YES
    <input type="radio" name="uradio" checked value="no">NO
  </label>
  <br /><br />
  <input type="submit" value="Submit" />
</form>

0
On

You can try this

formDataToJSON($('#form_example'));

# Create a function to convert the serialize and convert the form data
# to JSON
# @param : $('#form_example');
# @return a JSON Stringify
function formDataToJSON(form) {
    let obj = {};
    let formData = form.serialize();
    let formArray = formData.split("&");

    for (inputData of formArray){
        let dataTmp = inputData.split('=');
        obj[dataTmp[0]] = dataTmp[1];
    }
    return JSON.stringify(obj);
}
2
On

Here is a function that turns a formData object into a JSON-string.

  • Works with multiple entries and nested arrays.
  • Works with both numbered and named input name arrays.

For example you can have the following form fields:

<select name="select[]" multiple></select>
<input name="check[a][0][]" type="checkbox" value="test"/>

Usage:

let json = form2json(formData);

The function:

function form2json(data) {
        
        let method = function (object,pair) {
            
            let keys = pair[0].replace(/\]/g,'').split('[');
            let key = keys[0];
            let value = pair[1];
            
            if (keys.length > 1) {
                
                let i,x,segment;
                let last = value;
                let type = isNaN(keys[1]) ? {} : [];
                
                value = segment = object[key] || type;
                
                for (i = 1; i < keys.length; i++) {
                    
                    x = keys[i];
                    
                    if (i == keys.length-1) {
                        if (Array.isArray(segment)) {
                            segment.push(last);
                        } else {
                            segment[x] = last;
                        }
                    } else if (segment[x] == undefined) {
                        segment[x] = isNaN(keys[i+1]) ? {} : [];
                    }
                    
                    segment = segment[x];
                    
                }
                
            }
            
            object[key] = value;
            
            return object;
            
        }
        
        let object = Array.from(data).reduce(method,{});
        
        return JSON.stringify(object);
        
    }
0
On

Years later in vanillaJs (es6)

let body = new FormData()

body.set('key1', 'value AA')

body.set('key2', 'value BB')

let data = [...body.keys()].reduce( (acc, key, idx) => {
    acc[key] = body.get(key)
    return acc
} , {} )

console.log(JSON.stringify(data)) // {key1: 'value AA', key2: 'value BB'}

1
On

Easy To Use Function

I Have Created A Function For This

function FormDataToJSON(FormElement){    
    var formData = new FormData(FormElement);
    var ConvertedJSON= {};
    for (const [key, value]  of formData.entries())
    {
        ConvertedJSON[key] = value;
    }

    return ConvertedJSON
}

Example Usage

var ReceivedJSON = FormDataToJSON(document.getElementById('FormId'));

In this code I have created empty JSON variable using for loop I have used keys from formData Object to JSON Keys in every Itration.

You Find This Code In My JS Library On GitHub Do Suggest Me If It Needs Improvement I Have Placed Code Here https://github.com/alijamal14/Utilities/blob/master/Utilities.js

4
On

If you need support for serializing nested fields, similar to how PHP handles form fields, you can use the following function

function update(data, keys, value) {
  if (keys.length === 0) {
    // Leaf node
    return value;
  }

  let key = keys.shift();
  if (!key) {
    data = data || [];
    if (Array.isArray(data)) {
      key = data.length;
    }
  }

  // Try converting key to a numeric value
  let index = +key;
  if (!isNaN(index)) {
    // We have a numeric index, make data a numeric array
    // This will not work if this is a associative array 
    // with numeric keys
    data = data || [];
    key = index;
  }
  
  // If none of the above matched, we have an associative array
  data = data || {};

  let val = update(data[key], keys, value);
  data[key] = val;

  return data;
}

function serializeForm(form) {
  return Array.from((new FormData(form)).entries())
    .reduce((data, [field, value]) => {
      let [_, prefix, keys] = field.match(/^([^\[]+)((?:\[[^\]]*\])*)/);

      if (keys) {
        keys = Array.from(keys.matchAll(/\[([^\]]*)\]/g), m => m[1]);
        value = update(data[prefix], keys, value);
      }
      data[prefix] = value;
      return data;
    }, {});
}

document.getElementById('output').textContent = JSON.stringify(serializeForm(document.getElementById('form')), null, 2);
<form id="form">
  <input name="field1" value="Field 1">
  <input name="field2[]" value="Field 21">
  <input name="field2[]" value="Field 22">
  <input name="field3[a]" value="Field 3a">
  <input name="field3[b]" value="Field 3b">
  <input name="field3[c]" value="Field 3c">
  <input name="field4[x][a]" value="Field xa">
  <input name="field4[x][b]" value="Field xb">
  <input name="field4[x][c]" value="Field xc">
  <input name="field4[y][a]" value="Field ya">
  <input name="field5[z][0]" value="Field z0">
  <input name="field5[z][]" value="Field z1">
  <input name="field6.z" value="Field 6Z0">
  <input name="field6.z" value="Field 6Z1">
</form>

<h2>Output</h2>
<pre id="output">
</pre>

0
On

In my case form Data was data , fire base was expecting an object but data contains object as well as all other stuffs so i tried data.value it worked!!!

0
On

This solved my issue and this is for an Object

const formDataObject = (formData) => {

    for (const key in formData) {
        if (formData[key].startsWith('{') || formData[key].startsWith('[')) {
            try {
                formData[key] = JSON.parse(formData[key]);
                console.log("key is :", key, "form data is :", formData[key]);

            } catch (error) {
                console.log("error :", key);
            }
        }
    }

    console.log("object", formData)
}
0
On

Making use of toJSON as described in JSON.stringify()

If the value has a toJSON() method, it's responsible to define what data will be serialized.

Here is a little hack.

var fd = new FormData(document.forms[0]);

fd.toJSON = function() {
  const o = {};
  this.forEach((v, k) => {
    v = this.getAll(k);
    o[k] = v.length == 1 ? v[0] : (v.length >= 1 ? v : null);
  });
  return o;
};

document.write(`<pre>${JSON.stringify(fd)}</pre>`)
<form action="#">
  <input name="name" value="Robinson" />
  <input name="items" value="Vin" />
  <input name="items" value="Fromage" />
  <select name="animals" multiple id="animals">
    <option value="tiger" selected>Tigre</option>
    <option value="turtle" selected>Tortue</option>
    <option value="monkey">Singe</option>
  </select>
</form>

1
On

If you are using lodash it can be done concisely with fromPairs

import {fromPairs} from 'lodash';

const object = fromPairs(Array.from(formData.entries()));
0
On

Even though the answer from @dzuc is already very good, you could use array destructuring (available in modern browsers or with Babel) to make it even a bit more elegant:

// original version from @dzuc
const data = Array.from(formData.entries())
  .reduce((memo, pair) => ({
    ...memo,
    [pair[0]: pair[1],
  }), {})

// with array destructuring
const data = Array.from(formData.entries())
  .reduce((memo,[key, value]) => ({
    ...memo,
    [key]: value,
  }), {})
0
On

This works for me. Click here to see the details code

let formToJson = function(){
    let form = new FormData($("form#formData")[0]);
    //console.log(form);
    let jsonData = Object.fromEntries(form.entries());
    //console.log(jsonData);
    $("#jsonData").html(JSON.stringify(jsonData));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Document</title>
</head>
<body>
    <div class="">
        <form action="#" method="post" id="formData">
            <input type="text" name="fName" id="fName" value="Mad"><br>
            <input type="text" name="lName" id="lName" value="Coder"><br>
            <input type="button" onclick="formToJson()" value="Boom Yeah">
        </form>
    </div>
    <div id="jsonData">
    </div>
</body>
</html>

1
On

Worked for me

                var myForm = document.getElementById("form");
                var formData = new FormData(myForm),
                obj = {};
                for (var entry of formData.entries()){
                    obj[entry[0]] = entry[1];
                }
                console.log(obj);
0
On

Another approach that works with select multiple or inputs with same name attribute:

function form_to_json() {
  const form_data = new FormData(document.querySelector('form'))
  const uniqueKeys = [...new Set(form_data.keys())]  
  const obj = {}
  uniqueKeys.forEach((value, key) => {
    obj[value] = (form_data.getAll(value).length > 1) ? form_data.getAll(value) : form_data.get(value)
  })
  const json = JSON.stringify(obj)
  alert(json)
}
<form>
  <input type="text" name="name" value="Cesar"></br>
  <select name="cars" id="cars" multiple>
    <option value="volvo" selected>Volvo</option>
    <option value="saab" selected>Saab</option>
  </select>
  <input type="button" onclick="form_to_json()" value="Ok">
</form>

1
On

I've seen no mentions of FormData.getAll method so far.

Besides returning all the values associated with a given key from within a FormData object, it gets really simple using the Object.fromEntries method as specified by others here.

var formData = new FormData(document.forms[0])

var obj = Object.fromEntries(
  Array.from(formData.keys()).map(key => [
    key, formData.getAll(key).length > 1 ? 
      formData.getAll(key) : formData.get(key)
  ])
)

Snippet in action

var formData = new FormData(document.forms[0])

var obj = Object.fromEntries(Array.from(formData.keys()).map(key => [key, formData.getAll(key).length > 1 ? formData.getAll(key) : formData.get(key)]))

document.write(`<pre>${JSON.stringify(obj)}</pre>`)
<form action="#">
  <input name="name" value="Robinson" />
  <input name="items" value="Vin" />
  <input name="items" value="Fromage" />
  <select name="animals" multiple id="animals">
    <option value="tiger" selected>Tigre</option>
    <option value="turtle" selected>Tortue</option>
    <option value="monkey">Singe</option>
  </select>
</form>

1
On

Here is a function to convert FormData to plain JavaScript object which can be converted to JSON.

function formDataToObject(formData) {
    let object = {}

    const debug = (message) => {
        //console.log(message)
    }

    /**
     * Parses FormData key xxx`[x][x][x]` fields into array
     */
    const parseKey = (key) => {
        const subKeyIdx = key.indexOf('[');

        if (subKeyIdx !== -1) {
            const keys = [key.substring(0, subKeyIdx)]
            key = key.substring(subKeyIdx)

            for (const match of key.matchAll(/\[(?<key>.*?)]/gm)) {
                keys.push(match.groups.key)
            }
            return keys
        } else {
            return [key]
        }
    }

    /**
     * Recursively iterates over keys and assigns key/values to object
     */
    const assign = (keys, value, object) => {
        const key = keys.shift()
        debug(key)
        debug(keys)

        // When last key in the iterations
        if (key === '' || key === undefined) {
            return object.push(value)
        }

        if (Reflect.has(object, key)) {
            debug('hasKey ' + key)
            // If key has been found, but final pass - convert the value to array
            if (keys.length === 0) {
                if (!Array.isArray(object[key])) {
                    debug('isArray ' + object[key])
                    object[key] = [object[key], value]
                    return
                }
            }
            // Recurse again with found object
            return assign(keys, value, object[key])
        }

        // Create empty object for key, if next key is '' do array instead, otherwise set value
        if (keys.length >= 1) {
            debug(`undefined '${key}' key: remaining ${keys.length}`)
            object[key] = keys[0] === '' ? [] : {}
            return assign(keys, value, object[key])
        } else {
            debug("set value: " + value)
            object[key] = value
        }
    }

    for (const pair of formData.entries()) {
        assign(parseKey(pair[0]), pair[1], object)
    }

    return object
}

var formData = new FormData(document.querySelector('form'))

object = formDataToObject(formData)

console.log(object)
<form id="form">
<input type="text" name="test" value="BBBB">
<input type="text" name="testX" value="WEE">
<input type="text" name="testX" value="FFF">
<input type="text" name="testX[]" value="1">
<input type="text" name="test1[]" value="2">
<input type="text" name="test1[]" value="3">
<input type="text" name="test1[]" value="4">
<input type="text" name="test1[]" value="5">
<input type="text" name="test2[a]" value="5">
<input type="text" name="test2[a]" value="77">
<input type="text" name="test3[a]" value="67">
<input type="text" name="test3[1][]" value="22">
<input type="text" name="test3[1][]" value="33">
<input type="text" name="test3[1][]" value="44">
<input type="text" name="test4[xAx][1]" value="3">
<input type="text" name="test4[xAx][2]" value="23">
<input type="text" name="test4[xAx][3]" value="33">
</form>

0
On

If the following items meet your needs, you're in luck:

  1. You want to convert an array of arrays like [['key','value1'], ['key2','value2'] (like what FormData gives you) into a key->value object like {key1: 'value1', key2: 'value2'} and the convert it to a JSON string.
  2. You are targeting browsers/devices with the latest ES6 interpreter or are compiling with something like babel.
  3. You want the tiniest way to accomplish this.

Here is the code you'll need:

const data = new FormData(document.querySelector('form'));
const json = JSON.stringify(Array.from(data).reduce((o,[k,v])=>(o[k]=v,o),{}));

Hope this helps someone.

2
On

If you have multiple entries with the same name, for example if you use <SELECT multiple> or have multiple <INPUT type="checkbox"> with the same name, you need to take care of that and make an array of the value. Otherwise you only get the last selected value.

Here is the modern ES6-variant:

function formToJSON( elem ) {
  let output = {};
  new FormData( elem ).forEach(
    ( value, key ) => {
      // Check if property already exist
      if ( Object.prototype.hasOwnProperty.call( output, key ) ) {
        let current = output[ key ];
        if ( !Array.isArray( current ) ) {
          // If it's not an array, convert it to an array.
          current = output[ key ] = [ current ];
        }
        current.push( value ); // Add the new value to the array.
      } else {
        output[ key ] = value;
      }
    }
  );
  return JSON.stringify( output );
}

Slightly older code (but still not supported by IE11, since it doesn't support ForEach or entries on FormData)

function formToJSON( elem ) {
  var current, entries, item, key, output, value;
  output = {};
  entries = new FormData( elem ).entries();
  // Iterate over values, and assign to item.
  while ( item = entries.next().value )
    {
      // assign to variables to make the code more readable.
      key = item[0];
      value = item[1];
      // Check if key already exist
      if (Object.prototype.hasOwnProperty.call( output, key)) {
        current = output[ key ];
        if ( !Array.isArray( current ) ) {
          // If it's not an array, convert it to an array.
          current = output[ key ] = [ current ];
        }
        current.push( value ); // Add the new value to the array.
      } else {
        output[ key ] = value;
      }
    }
    return JSON.stringify( output );
  }
6
On

In 2019, this kind of task became super-easy.

JSON.stringify(Object.fromEntries(formData));

Object.fromEntries: Supported in Chrome 73+, Firefox 63+, Safari 12.1

As mentioned in the comments, please note: FormData can contain multiple values with the same key (e.g. checkboxes with the same name). Object.fromEntries() throws away duplicates and only keeps the last one.

1
On

if you want the json string :

var jsonStr =  JSON.stringify($('#formId').serializeObject());

if you want a json Object

var jsonObj =  JSON.parse(JSON.stringify($('#formId').serializeObject()));
0
On

I know its late, but here's the solution;

new URLSearchParams(new FormData(formElement)).toString()

Now, this can be sent as the body. Sadly, its not JSON.

0
On

EDIT: I saw there already is an answer which yields very similar results.

Two main differences:

  • This doesn't treat numeric keys as array indices, rather they still count as object keys. Might not be the proper behaviour but I've personally never written forms that use this notation, might update it.
  • This is not a recursive function, this is obviously not a pro or a con

Ignore any lack of efficiency. This will handle unlimited nesting, and duplicate keys for arrays. This obviously will not convert things such as files, but I don't need it so I didn't add it.

Here's a JSFiddle with an example conversion that can be achieved with this function

A great example usage for this (which is also my use case) would be to create a new FormData object from an html form element, and easily convert it to JSON for sending.

/**
 * @param {FormData} formData
 * @return {Object}
 */
function formDataToObject(formData) {
    const object = {};
    for (let pair of formData.entries()) {
        const key = pair[0];
        const value = pair[1];
        const isArray = key.endsWith('[]');
        const name = key.substring(0, key.length - (2 * isArray));
        const path = name.replaceAll(']', '');
        const pathParts = path.split('[');
        const partialsCount = pathParts.length;
        let iterationObject = object;
        for (let i = 0; i < partialsCount; i++) {
            let part = pathParts[i];
            let iterationObjectElement = iterationObject[part];
            if (i !== partialsCount - 1) {
                if (!iterationObject.hasOwnProperty(part) || typeof iterationObjectElement !== "object") {
                    iterationObject[part] = {};
                }
                iterationObject = iterationObject[part];
            } else {
                if (isArray) {
                    if (!iterationObject.hasOwnProperty(part)) {
                        iterationObject[part] = [value];
                    } else {
                        iterationObjectElement.push(value);
                    }
                } else {
                    iterationObject[part] = value;
                }
            }
        }
    }

    return object;
}
0
On

just use:

JSON.stringify(Object.fromEntries(formData));

for checkbox input or multiple select, use getAll function:

let formData = new FormData(form);
let obj = Object.fromEntries(new FormData(form));
let hobbies = formData.getAll('hobbies'); // hobbies is checkbox's name
let data = {...obj, hobbies: JSON.stringify(hobbies)};
0
On

I am arriving late here. However, I made a simple method that checks for the input type="checkbox"

var formData = new FormData($form.get(0));
        var objectData = {};
        formData.forEach(function (value, key) {
            var updatedValue = value;
            if ($('input[name="' + key + '"]').attr("type") === "checkbox" && $('input[name="' + key + '"]').is(":checked")) {
                updatedValue = true; // we don't set false due to it is by default on HTML
            }
            objectData[key] = updatedValue;
        });
var jsonData = JSON.stringify(objectData);

I hope this helps somebody else.

0
On

For my purposes that included multiselects like checkboxes, this was good:

JSON.stringify(Array.from((new FormData(document.querySelector('form'))).entries()).reduce((map = {}, [key, value]) => {
    return {
        ...map,
        [key]: map[key] ? [...map[key], value] : value,
    };
}, {}));
0
On

Abusive one-liner!

Array.from(fd).reduce((obj, [k, v]) => ({...obj, [k]: v}), {});

Today I learned firefox has object spread support and array destructuring!

0
On

Here is a simple elegant solution that works:

const data = [...new FormData(formData)]

The full code example for me

            <form
                onSubmit={event => {
                    event.preventDefault()
                    const data = [...new FormData(formData)]
2
On

Here's a way to do it in a more functional style, without the use of a library.

Array.from(formData.entries()).reduce((memo, [key, value]) => ({
  ...memo,
  [key]: value,
}), {});

Example:

document.getElementById('foobar').addEventListener('submit', (e) => {
  e.preventDefault();

  const formData = new FormData(e.target);
  const data = Array.from(formData.entries()).reduce((memo, [key, value]) => ({
    ...memo,
    [key]: value,
  }), {});
  document.getElementById('output').innerHTML = JSON.stringify(data);
});
<form id='foobar'>
  <input name='baz' />
  <input type='submit' />
</form>

<pre id='output'>Input some value and submit</pre>

0
On

I think this is the simplest way to get the result you want from a formData FormData object:

const jsonData = {};

for(const [key, value] of formData) {
    jsonData[key] = value;
}
0
On

+1 with everyone who says it's annoying that there isn't an inbuilt way to do this!

One thing worth noting is that if only one option is selected in a multi select, many answers including the accepted answer will only return a string with a single value instead of an array (for example, try clicking only "cats" on the accepted answer and you will get {"pets":"cats"} instead of {"pets":["cats"]}). This may not be an issue depending on use case, but if you are using an API which is expect an array instead of a single string this will cause an exception. To account for this, we can get all select elements with "multiple" as an attribute. Here is code based on the accepted answer which accounts for this case:

    const submit = document.getElementById("submit");

const getFormInfo = () => {
  const form = document.getElementById("form");
  let allMultiSelectFields = []
  document.querySelectorAll('select[multiple]').forEach(element => allMultiSelectFields.push(element.getAttribute("name")))
  return {
    formData: new FormData(form),
    mutliSelectFields: allMultiSelectFields
  }
}

const toJson = function(event) {
  const {
    formData,
    mutliSelectFields
  } = getFormInfo()
  event.preventDefault();
  let object = {};
  formData.forEach((value, key) => {
    if (mutliSelectFields.includes(key)) {
      if (Reflect.has(object, key)) object[key].push(value)
      else object[key] = [value]
      return
    }
    object[key] = value
  });
  let json = JSON.stringify(object);
  console.log(json);
};

submit.addEventListener("click", toJson);