'How to convert FormData (HTML5 object) to JSON
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.
Solution 1:[1]
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 a XML HTTP request 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:
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.
Solution 2:[2]
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.
Solution 3:[3]
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>
Solution 4:[4]
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 );
}
Solution 5:[5]
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>
Solution 6:[6]
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);
});
Solution 7:[7]
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>
Solution 8:[8]
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 key
s 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
Solution 9:[9]
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>
Solution 10:[10]
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,
}), {})
Solution 11:[11]
If the following items meet your needs, you're in luck:
- 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. - You are targeting browsers/devices with the latest ES6 interpreter or are compiling with something like babel.
- 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.
Solution 12:[12]
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;
}
Solution 13:[13]
If you are using lodash it can be done concisely with fromPairs
import {fromPairs} from 'lodash';
const object = fromPairs(Array.from(formData.entries()));
Solution 14:[14]
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);
}
Solution 15:[15]
Abusive one-liner!
Array.from(fd).reduce((obj, [k, v]) => ({...obj, [k]: v}), {});
Today I learned firefox has object spread support and array destructuring!
Solution 16:[16]
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);
}
Solution 17:[17]
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>
Solution 18:[18]
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)
}
Solution 19:[19]
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>
Solution 20:[20]
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);
Solution 21:[21]
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!!!
Solution 22:[22]
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.
Solution 23:[23]
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()));
Solution 24:[24]
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.
Solution 25:[25]
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'}
Solution 26:[26]
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"]}
Solution 27:[27]
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>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow