Skip to content Skip to sidebar Skip to footer

How To Create A Nested Object (JSON) Of A Form Input Values Based On The Input Name In Vanilla JavaScript?

//lets say the form is like below

Solution 1:

You can use jQuery and use the serializeArray() method like this var jsonData = $('form').serializeArray();:

It doesn't match your sample object but it does what your question asked.

Once you have the fields in an Array you can manipulate your object however you want. I can't quite follow the logic of how you could ever arrive with that object from the form name attributes so I can't even attempt to map it.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id="myform">
      <input name="foo" value="parent"/>
      <input name="foo.cat.bar" value="child1"/>
      <input name="foo.cat.biz" value="child2"/>
      <input name="foo.cat.biz.dog.bar" value="child3"/>
  </form>
  <input id='btnSerialize' value='Serialize' type='button' onclick='serializeForm()' />
  <div id='result'></div>
  <script>
 
  function serializeForm()
  {
    var jsonData = $('form').serializeArray();
    var jsonString = JSON.stringify(jsonData);
    $('#result').html(jsonString);
  }

  </script>

If you change your form names so you can have a valid logical structure than in Plain javascript:

/*
{
  "foo": {
    "bar": "parent",
    "biz": "parent",
    "cat": {
      "bar": "child2achild2a,child2b",
      "biz": {
        "dog": {
          "bar": "child3"
        }
      }
    }
  }
}
*/
<form id="myform">
  <input name="foo.bar" value="parent" />
  <input name="foo.biz" value="parent" />
  <input name="foo.cat.bar" value="child2a" />
  <input name="foo.cat.bar" value="child2b" />
  <input name="foo.cat.biz.dog.bar" value="child3" />
</form>
<script>
  function serialize() {
    var elements = document.querySelectorAll('#myform input');
    var data = {};
    for (var i = 0; i < elements.length; i++) {
      var el = elements[i];
      var val = el.value;
      if (!val) val = "";
      var fullName = el.getAttribute("name");
      if (!fullName) continue;
      var fullNameParts = fullName.split('.');
      var prefix = '';
      var stack = data;
      for (var k = 0; k < fullNameParts.length - 1; k++) {
        prefix = fullNameParts[k];
        if (!stack[prefix]) {
          stack[prefix] = {};
        }
        stack = stack[prefix];
      }
      prefix = fullNameParts[fullNameParts.length - 1];
      if (stack[prefix]) {

        var newVal = stack[prefix] + ',' + val;
        stack[prefix] += newVal;
      } else {
        stack[prefix] = val;
      }
    }
    console.log(data);

  }
</script>
<input type="button" value="go" onclick="serialize()" />
<p><br /></p>
<p><br /></p>

Solution 2:

Here you go. I've included an explanation in the comments...

function getFormData() {
    /* return nested array combined
       into groups of two. See question @ 
       https://stackoverflow.com/a/31352555/4746328 */
    function groupIntoPairs(arr) {
        var temp = arr.slice();
        var out = [];

        while (temp.length) {
            out.push(temp.splice(0,2));
        }

        return out;
    }

    /* create a storage object */
    var data = {},
    /* get 'input' elements as an array */
    inputs = [].slice.call(document.getElementById('myform').querySelectorAll('input')),
    /* additional variables */
    name, hold, splits, L, dKey;

    /* loop through input elements */
    inputs.forEach(function(n) {
        name = n.name;

        /* for holding key strings */
        hold = '';

        /* split the 'name' at '.'
           and group into pairs */ 
        splits = groupIntoPairs( name.split('.') );

        /* index of last item in 'splits' */
        L = splits.length - 1;

        /* if 'splits' has only one
           item add the name-value pair
           to 'data' straight away */
        if (L === 0) {
            data[name] = n.value;
        } else {
            /* loop 'splits' to create keys */
            splits.forEach(function(x, i) {
                /* combine key strings until
                   last item in 'splits' */
                if (i !== L) hold += '.' + x.join('.');
            });

            /* define the key */
            dKey = hold.slice(1);

            /* create 'data[dKey]' Object if
               it doesn't exist or use it
               again if it does */
            data[dKey] = data[dKey] || {};

            /* add last item in 'splits' as 
               key for 'data[dKey]' and 
               assign current n.value */
            data[dKey][splits[L][0]] = n.value;                
        }
    });
    /* return 'data' object */
    return data;
}

console.log('data:', JSON.stringify(getFormData(), null, 4));
/* => data: {
    "foo": "parent",
    "foo.cat": {
        "bar": "child1",
        "biz": "child2"
    },
    "foo.cat.biz.dog": {
        "bar": "child3"
    }
}
*/

Hope that helped.


Post a Comment for "How To Create A Nested Object (JSON) Of A Form Input Values Based On The Input Name In Vanilla JavaScript?"