How to serialize a form into an object (with tree structure)?

I have a form

<form>
    <input type="text" name="Name" />
    <input type="checkbox" name="Feature.Translate" />
    <input type="checkbox" name="Feature.Share" />

    <input type="submit" value="Convert into an object" />
</form>

I want to convert it in an object

{
    Name: "John Connor's Terminator",
    Feature:
    {
        Translate: true // if checked
        // Share wasn't checked
    }
}

How can I map the form to an object that has this tree structure?

Answers:

Answer

Add this method to help you build the tree

// add keys to an object as a tree
// ["a", "b", "c"] will generate
// a { b: { c: def } }
// def is the value of the leaf node
var AddToTree = function(obj, keys, def)
{
    for (var i = 0, length = keys.length; i < length; ++i)
        obj = obj[keys[i]] = i == length - 1 ? def : obj[keys[i]] || {};
};

Create a function for a jQuery selector that will convert the form in an object

$.fn.serializeObject = function()
{
   var o = {}; // final object
   var a = this.serializeArray(); // retrieves an array of all form values as
                                  // objects { name: "", value: "" }

   $.each(a, function() {
       var ns = this.name.split("."); // split name to get namespace
       AddToTree(o, ns, this.value); // creates a tree structure
                                     // with values in the namespace
   });

   return o;
};

With these two functions define you can set an event on the submit button:

$(":submit").click(function(e){
    // contains the object from the form
    // respecting element namespaces
    var obj = $("form").serializeObject();
});
Answer

Something like the following should work:

function serializeData() {
    //this is where we'll store our serialized data
    var serializedData = {};

    //iterate over input, select, and textarea elements
    jQuery("input, select, textarea").each(function(index) {
       var $element = jQuery(this);
       var name = $element.attr("name");

       //we only want to serialize the element if it has a 'name' attribute
       if(typeof name != "undefined") {

          //split on the . to get an array
          var parts = name.split(/\./);

          //start building the serialized data
          var currentPart = serializedData;
          for(var i = 0; i < parts.length; i++) {

              //if this particular element doesn't already exist in our hash, create it
              //and initialize it to an empty hash
              if(typeof serializedData[parts[i]] == "undefined") {
                  currentPart[parts[i]] = {};
              }

              //if we're currently looking at the very last element in the array then
              //it means that we need to set its value to the value of the corresponding
              //input element. Otherwise, it means that there are still keys within the
              //array and so we set `currentPart` to the new hash that we just created
              if(i == parts.length - 1) {

                  //if the element is a checkbox or a radio, we need to see if it's checked
                  //instead of looking at its value
                  if($element.attr("type").toLowerCase() == "checkbox" || $element.attr("type").toLowerCase() == "radio") {
                      currentPart[parts[i]] = $element.is(":checked");
                  }

                  else {
                     currentPart[parts[i]] = $element.val();
                  }
              }

              else {            
                  currentPart = currentPart[parts[i]];
              }                   
          }
       }
    });

    console.log(serializedData);
}

Check out the fiddle.

All you need to do now is to bind serializeData to the submit event on the form.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.