Home > OS >  How to convert FormData to JSON recursively (retaining the hierarchy)?
How to convert FormData to JSON recursively (retaining the hierarchy)?

Time:11-22

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]" ..>

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?

CodePudding user response:

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"
    }
  ]
}

CodePudding user response:

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, and with JSON object this will be incorrecty parsed  -->
    <input type="hidden" name="Y[Z][]" value="101" />
    <input type="hidden" name="Y[Z][]" value="102" />
</form>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related