Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert formData with nested keys to JS Object

Tags:

javascript

I've been trying to get a nested object from formData from a form with nested keys like the below:

<input name="item[0][id]" value="0121"/>
<input name="item[0][name]" value="Birmingham"/>
<input name="item[1][id]" value="01675"/>
<input name="item[1][name]" value="Warwickshire"/>

To be formatted as an object like this:

{
  'item': [
    {
      'id': '0121',
      'name': 'Birmingham'
    },
    {
      'id': '01675',
      'name': 'Warwickshire'
    }
  ]
}

Not:

{
  'item[0][id]': '0121',
  'item[0][name]': 'Birmingham',
  'item[1][id]': '01675',
  'item[1][name]': 'Warwickshire'
}

Currently I'm using the below, which is outputting in the format above.

const formData = new FormData(this.form);
const object = Object.fromEntries(formData);

Essentially, I'd like to have the form data formatted as it would be when it gets received by PHP for example.

like image 688
WarrenR Avatar asked Oct 15 '25 08:10

WarrenR


1 Answers

You could use something like lodash's _.set function, or else an implementation of the same feature in vanilla JavaScript, which I will use in below snippet:

// This function is taken from https://stackoverflow.com/a/54733755/5459839
function deepSet(obj, path, value) {
    if (Object(obj) !== obj) return obj; // When obj is not an object
    // If not yet an array, get the keys from the string-path
    if (!Array.isArray(path)) path = path.toString().match(/[^.[\]]+/g) || []; 
    path.slice(0,-1).reduce((a, c, i) => // Iterate all of them except the last one
         Object(a[c]) === a[c] // Does the key exist and is its value an object?
             // Yes: then follow that path
             ? a[c] 
             // No: create the key. Is the next key a potential array-index?
             : a[c] = Math.abs(path[i+1])>>0 === +path[i+1] 
                   ? [] // Yes: assign a new array object
                   : {}, // No: assign a new plain object
         obj)[path[path.length-1]] = value; // Finally assign the value to the last key
    return obj; // Return the top-level object to allow chaining
}

// Use it for formData:
function formDataObject(form) {
    const formData = new FormData(form);
    const root = {};
    for (const [path, value] of formData) {
        deepSet(root, path, value);
    }
    return root;
}

// Example run
const result = formDataObject(document.forms[0]);
console.log(result);
<form>
    <input name="item[0][id]" value="0121"/>
    <input name="item[0][name]" value="Birmingham"/>
    <input name="item[1][id]" value="01675"/>
    <input name="item[1][name]" value="Warwickshire"/>
</form>
like image 195
trincot Avatar answered Oct 16 '25 22:10

trincot



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!