4

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.

1 Answer 1

7

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>

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.