23

I've been searching for hours for this and haven't found an answer. Please read through the whole question before flaming! :)

I have a form similar to this:

<form id="sample">
 <input name="name" type="text" value="name value" />

 <input name="phone[0][type]" type="text" value="cell" />
 <input name="phone[0][number]" type="text" value="000" />

 <input name="phone[1][type]" type="text" value="home" />
 <input name="phone[1][number]" type="text" value="111" />
</form>

And need to be able to serialize it to this:

{
 name: 'name value',

 phone: [
  {
   type: 'cell',
   number: '000'
  },
  {
   type: 'home',
   number: '111'
  }
 ]
}

I have tried most answers on SO including jquery-json libraries and most of them return something like this:

{
 'name': 'name value',
 'phone[0][type]': 'cell',
 'phone[0][number]': '000',
 'phone[1][type]': 'home',
 'phone[1][number]': '111',
}

This is something I cannot use! :P

Thanks everyone in advance.

George Antoniadis
  • 649
  • 3
  • 8
  • 14

6 Answers6

19

Try this code I wrote for you... Works fine for me, just using your data result. You can work on it and make a simple jQuery plugin...

The sample need JSON.stringify to work fully.

var d = {
    'name': 'name value',
    'phone[0][type]': 'cell',
    'phone[0][number]': '000',
    'phone[1][type]': 'home',
    'phone[1][number]': '111',
};

$(document).ready(function(){

    arrangeJson(d);
    alert(JSON.stringify(d));
});

function arrangeJson(data){
    var initMatch = /^([a-z0-9]+?)\[/i;
    var first = /^\[[a-z0-9]+?\]/i;
    var isNumber = /^[0-9]$/;
    var bracers = /[\[\]]/g;
    var splitter = /\]\[|\[|\]/g;

    for(var key in data) {
        if(initMatch.test(key)){
            data[key.replace(initMatch,'[$1][')] = data[key];
        }
        else{
            data[key.replace(/^(.+)$/,'[$1]')] = data[key];
        }
        delete data[key];
    }


    for (var key in data) {
        processExpression(data, key, data[key]);
        delete data[key];
    }

    function processExpression(dataNode, key, value){
        var e = key.split(splitter);
        if(e){
            var e2 =[];
            for (var i = 0; i < e.length; i++) {
                    if(e[i]!==''){e2.push(e[i]);} 
            }
            e = e2;
            if(e.length > 1){
                var x = e[0];
                var target = dataNode[x];
                if(!target){
                    if(isNumber.test(e[1])){
                        dataNode[x] = [];
                    }
                    else{
                        dataNode[x] ={}
                    }
                }
                processExpression(dataNode[x], key.replace(first,''), value);
            }
            else if(e.length == 1){
                dataNode[e[0]] = value;
            }
            else{
                alert('This should not happen...');
            }
        }
    }
}
Juliano
  • 2,422
  • 21
  • 23
  • Works like magic. Had a little modification to it to handle a situation where your List is in the form var d = { 'name': 'name value', 'phone[0].type': 'cell', 'phone[0].number': '000', 'phone[1].type': 'home', 'phone[1].number': '111', }; The result has (.) in from of the inner list Key, So I added after the first for loop in the processExpression() function. – Gabriel Ojomu Feb 05 '16 at 16:13
  • _key_ is twice declared in the function. – robsch May 14 '16 at 14:16
6

There is also the following library

http://code.google.com/p/form2js/

Tom
  • 12,591
  • 13
  • 72
  • 112
2

This worked very well for me. This doesn't need to have the form2js library.

$.fn.serializeObject = function serializeObject() {
        var o = {};
        var a = this.serializeArray();
        $.each(a, function () {
            if (o[this.name] !== undefined) {
                if (!o[this.name].push) {
                    o[this.name] = [o[this.name]];
                }
                o[this.name].push(this.value || '');
            } else {
                o[this.name] = this.value || '';
            }
        });
        return o;
    };

To serialise the form data I used this code then.

JSON.stringify($(this).serializeObject());//'this' points to the form

If you have any doubts please feel free to add comment.

Amit
  • 2,495
  • 14
  • 22
1

With this structure, I don't think any JSON library can do all the work. So, I think that is more easy to write our own conversion loop.

Here is the code to your serialization: http://jsfiddle.net/7MAUv/1/

The logic is pretty simple, the secret is the eval to run Strings like dynamic commands. I tried to make it as easier as possible, almost all lines are commented.

BTW, feels free to make questions.

Erick Petrucelli
  • 14,386
  • 8
  • 64
  • 84
  • Your code works perfectly Erick. Thank you very much for posting it. I will try and see if can be done without the eval part but should be awesome for now. – George Antoniadis Sep 09 '10 at 14:04
0

Its not exactly what you asked for, but if you are using jQuery library and need your complex form serialized for a purpose of sending it in ajax, you can use sth like this

ajaxRunning = $.ajax(
   "?"+$('#yourForm').serialize(),
    {
       data: {
           anotherData: 'worksFine',
           etc: 'still works'
       },
       success: function(result) {
           doSth();
       },
       dataType: "json"
});

you can use in $.post and $.get as well

nJoy!

Wax Cage
  • 788
  • 2
  • 8
  • 24
0

Another library that solves this issue is jquery.serializeJSON by Mario Izquierdo. It works and extends jQuery.

robsch
  • 9,358
  • 9
  • 63
  • 104