294

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.

6
  • 2
    What are you trying to do? Does JSON.stringify() helps? Maybe you try to fix something that may be done in other way? Commented Jan 3, 2017 at 7:39
  • 8
    Is not duplicate since I do not want to convert a javascript object to a json, nor do I want to use Jquery.serialize () Commented Jan 3, 2017 at 13:34
  • check this : stackoverflow.com/a/39248551/6293856 Commented Jul 23, 2019 at 7:10
  • Works for nested forms too: stackoverflow.com/a/70057955/2377343 Commented Nov 21, 2021 at 20:04
  • Much depends on the goal you are pursuing. If you want send JSON through the XHR request, you don't need the conversion that has issue with multiple values. You can just use URLSearchParams API like: let data = new URLSearchParams(formData) Commented Nov 23, 2022 at 12:28

38 Answers 38

384

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.

Sign up to request clarification or add additional context in comments.

18 Comments

As mentioned in the answer from @TomasPrado make sure you don't need support for IE11.
This doesn't work with multi select form elements since they share the same key you end up overwriting the values returning only the last selected element
@Sean I gave an answer that works with multiple values for <SELECT MULTIPLE> and <INPUT type="checkbox"> with same name, by converting the value to an array.
formData is not a serie. how you can iterate? accepted answer but something missed.
Unless a need for multi selects etc.. the answer with JSON.stringify(Object.fromEntries(formData)); is so much nicer
|
360

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.

6 Comments

This doesn't seem to work correctly on forms that have multiple fields with same name.
It is 2020 and this do not handle multiple selected values of <select multiple> or <input type="checkbox"> 😞
Better to use formData.entries: JSON.stringify(Object.fromEntries(formData.entries()));
@Kohver, better why? Does it remove duplicates? What kind of problems does it solve to make it better?
Are we sure this works correctly? I tried it for FormData that had multiple values on the same key, and it only printed the last one in the JSON string.
|
32

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>

2 Comments

I really like this answer but still do not handle multiple items. I posted a new answer based on this one to handle those cases.
I advise to replace pair with [key, value] in order to exploit destructuring and improve readibility
28

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>

2 Comments

From my point of view, this method using getAll is most practice and easy to understand. But the selected answer is good too. Thanks @OpSocket, I think this has a better performance.
this is the most elegant solution that far. thank you @OpSocket
16

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 );
  }

2 Comments

But when only 1 checked in checkbox, the value is still a single string, intead of being an array.
That is correct. Since you can have multiple type of fields with the same name, I made the decision to set the value for first occurrence, and only convert it to an array if multiple values was found. I do not want to first scan the form to find field names that could result in arrays.
13

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>

4 Comments

Need to update default value of "data" from array "[]" to object "{}" in "function update(data, keys, value) {" it removes blank array issue.
I also suggest to add an array filter before reduce to remove empty fields from the final object
@ChintanMathukiya Maia Can you share the sample input for which you are having unexpected output?
@Ednilson Can you share the sample data for which you are seeing empty array output?
9

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);

});

7 Comments

This does not produce json
@Liam Have you tried this with form elements ? And let me know why it doesn't produce JSON object ?
There is no such thing as a json object. Json is a string notation
@Liam After the object created they can use JSON.stringify(result). And I have edited my answer. Please check it. And withdraw the down vote.
You can also make the for of statement more expressive if you're using ES6: for (const [key, value] of formData.entries())
|
8

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)};

1 Comment

Object.fromEntries fails for array values when name is duplicated.
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>

3 Comments

Array.from(fd).reduce((obj, [k, v]) => ({...obj, [k]: v}), {}); hotshot version es2018
@nackjicholson Yeap, you are right, omitting .entries() and the [k,v] element simplify the code. I will rewrite the code to include these improvements. However yours will still overwrite on repeated values.
While I an appreciate the effort - code like this is absurd. Nobody wants to look at letters for variables and objects, this is not 1985.
6

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);
        
    }

2 Comments

This, for me, seems to be the best answer and covers the variety of possible input names. Thanks for sharing. (Just add function before the first statement and you are golden.)
function added, thanks!
6

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

1 Comment

This do not handle multiple selected values of <select multiple> or <input type="checkbox">.
4

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.

Comments

4

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;
}

Comments

3

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,
  }), {})

Comments

3

Abusive one-liner!

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

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

Comments

3

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>

Comments

3

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>

1 Comment

this is the most complete answer, thank you
2

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

import {fromPairs} from 'lodash';

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

1 Comment

Doesn't work for nested JSON.
2

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);
}

Comments

2

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;
}

Comments

1

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);

1 Comment

It will not handle multiple selected values of <select multiple> or <input type="checkbox">
1

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>

Comments

1

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"]}

Comments

1

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,
    };
}, {}));

Comments

1

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)
}

Comments

1

I didn't see an answer for TypeScript. Moreover, this question is marked as duplicate and is closed.

So I present my solution using zod schema.

const createJSONFromFormData = (data: FormData, zodSchema: z.AnyZodObject) => {
  const keys = Object.keys(zodSchema.shape) as unknown as Array<keyof z.infer<typeof zodSchema>>;
  const arrayKeys = keys.filter(key => zodSchema.shape[key] instanceof z.ZodArray);

  const values = Object.fromEntries(
    Array.from(data.keys()).map(key => [key, arrayKeys.includes(key) ? data.getAll(key) : data.get(key)]),
  );

  console.debug("Debug values createJSONFromFormData", JSON.stringify(values));

  return values;
};

The idea is to use schema.shape from zod to see if some properties are supposed to be an array. If so, it uses data.getAll instead of data.get.

Comments

1

When you use the spread operator (...) on a FormData iterable, it converts the iterable into an array of key-value pairs which is called (entries). You can then use Object.fromEntries() to transform these entries into a plain object.

const myForm = new FormData()
myForm.set("name", "Ram")
const myFormDataObj = Object.fromEntries([...myForm])

console.log(myFormDataObj) // Output: { name: "Ram" }

1 Comment

Does not work with checkboxes and list of values with same name. FormData.get('checkName') returns an array but Object.fromEntries returns a string.
0

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!!!

Comments

0

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.

Comments

0

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>

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.