2

I know there were other questions asked here, but none of them addresses this specific issue.


When we have form like:

<input name="A" .. />
<input name="B[x1]" .. />
<input name="C[y][z]".. />

then all solutions suggested here just create the flat-hierarchy JSON, like:

{
   "A" : "1",
   "B[x1]" : "2" 
}

However, the correct form-data it needs to be created should be :

{
   "A" : "1",
   "B" : {
      "x1":"2
   }
}

Is there any standard/builtin JS approach for that?

6
  • There's no built-in function for this, but I would assume you could amend the answers to do what you want? Commented Nov 21, 2021 at 17:01
  • Does this answer your question? Serialize complex form to JSON object using jQuery Commented Nov 21, 2021 at 17:09
  • Solution that will get you a lot closer to what you want stackoverflow.com/a/53245088/1175966 Commented Nov 21, 2021 at 17:13
  • I suspect there is probably a library out there that will do this but not sure what it is. The QS library might help. Look at it's parse method Commented Nov 21, 2021 at 17:33
  • @charlietfl thanks for the answers, I do appreciate. I've tried looked into that, and it seemed somehow large/complex code (though might be advanced and sophisticated), and ATM, I preferred the custom function I've posted below. Commented Nov 21, 2021 at 20:00

2 Answers 2

2

Surprising, but JS doesn't have any native/common way to achieve this goal. The temporary solution (beware, this is not extensively tested) I made for me needs:

function formItemsToJson(FormElement){    
    let formDataEntries = new FormData(FormElement).entries();
    const handleChild = function (obj,keysArr,value){
        let firstK = keysArr.shift();
        firstK=firstK.replace(']','');
        if (keysArr.length==0){
            if (firstK=='') {
                if (!Array.isArray(obj)) obj=[];
                obj.push(value);
            }
            else obj[firstK] = value; 
        } 
        else{
            if (firstK=='') obj.push(value); 
            else {
                if ( ! ( firstK in obj) ) obj[firstK]={};
                obj[firstK] = handleChild(obj[firstK],keysArr,value);
            }
        }
        return obj;
    };
    let result = {};
    for (const [key, value]  of formDataEntries )
        result= handleChild(result, key.split(/\[/), value); 
    return result;
}


// USAGE :  
alert( JSON.stringify( formItemsToJson( document.querySelector('#myForm') ), null, 2 ) );
<form id="myForm">
    <input type="hidden" name="A" value="11" />
    <input type="hidden" name="C[E][m1]" value="22" />
    <input type="hidden" name="C[E][m2]" value="23" />

    <!-- only FormData can parse this below, because with JSON.stringify the below object will degrade,as same keys will be in conflict  -->
    <input type="hidden" name="Y[Z][]" value="101" />
    <input type="hidden" name="Y[Z][]" value="102" />
</form>

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

2 Comments

If the function converts to json why not out the stringify inside it too? That way it will actually return json
@evolutionxbox same keys (Y[Z][] ) will be in conflict, only FormData seems to handle them.
1

Using Object.fromEntries to iterate over entries;
Each loop grab key : value. if key doesn't contain [ add it to object res, else get old values(object) of that key e.i. B and add them the current with its value.
we could use also use Regex to grab nested key and values dynamically instead of indexOf

const obj = {
  A: "1",
  "B[x1]": "2",
  "B[x2]": "3",
};
res = {};
Object.entries(obj).forEach((entry) => {
  const [key, value] = entry;
  if (!key.includes("[")) res[key] = value;
  else {
    const parentKey = key.slice(0, key.indexOf("["));
    const childKey = key.slice(key.indexOf("[") + 1, -1);
    res[parentKey] = res[parentKey] ?? [];
    res[parentKey].push({ [childKey]: value });
  }
});
res; //?

Result:

{
  "A": "1",
  "B": [
    {
      "x1": "2"
    },
    {
      "x2": "3"
    }
  ]
}

2 Comments

I've tried, but couldn't make it work with i.e. B[x2][y1] keys, they spoil everything. Only the function i've made (& posted below) helped at this moment. anyway, thanks for answer.
Sorry, I didn't pay attention to these cases of deep nested B[x2][y1]!

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.