Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Convert formData with nested keys to JS Object

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:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

{
  '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.

>Solution :

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>
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading