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?

T.Todua
  • 53,146
  • 19
  • 236
  • 237
  • There's no built-in function for this, but I would assume you could amend the answers to do what you want? – evolutionxbox Nov 21 '21 at 17:01
  • Does this answer your question? [Serialize complex form to JSON object using jQuery](https://stackoverflow.com/questions/3672995/serialize-complex-form-to-json-object-using-jquery) – evolutionxbox Nov 21 '21 at 17:09
  • Solution that will get you a lot closer to what you want https://stackoverflow.com/a/53245088/1175966 – charlietfl Nov 21 '21 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](https://www.npmjs.com/package/qs) might help. Look at it's parse method – charlietfl Nov 21 '21 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. – T.Todua Nov 21 '21 at 20:00
  • @evolutionxbox no, they doesn't answer to my question, and only the below answer helped me. – T.Todua Nov 21 '21 at 20:01

2 Answers2

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>
T.Todua
  • 53,146
  • 19
  • 236
  • 237
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"
    }
  ]
}
XMehdi01
  • 5,538
  • 2
  • 10
  • 34
  • 1
    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. – T.Todua Nov 21 '21 at 19:58
  • Sorry, I didn't pay attention to these cases of deep nested `B[x2][y1]`! – XMehdi01 Nov 21 '21 at 20:16