2
\$\begingroup\$

I am working on a small serialization function which serializes form input to json.

Here is the fiddle: http://jsfiddle.net/jdQfj/2/

I have currently no idea how to split up the array declarations let alone a combination of array and object declaration. However the function works good with infinite object nestings and normal values. But I could believe that there is optimization room.

jQuery.fn.serializeObject = function() {
    var o = {};
    var a = this.serializeArray();

    $.each(a, function() {

        // check if object
        if (this.name.indexOf('.') !== -1) {
            var path = this.name.split('.');

            var current = o;
            for (var i = 0; i < path.length; i++) {
                if (i === (path.length - 1)) {
                    current[path[i]] = this.value;
                } else {
                    if (current[path[i]] === undefined) {
                        current[path[i]] = {};
                    }
                }
                current = current[path[i]];
            }

        // check if array
        } else if (this.name.indexOf('[') !== -1 && this.name.indexOf(']')) {
            console.log(this.name + ' is an array');

            // has to get implmented

        // normal value
        } else {
            o[this.name] = this.value;
        }

    });

    return o;
};
\$\endgroup\$
  • 1
    \$\begingroup\$ I thought it would hard to know how the code works without an example. However when it helps you I can do ;) \$\endgroup\$ – bodokaiser Sep 3 '12 at 4:56
2
\$\begingroup\$

Here's what I came up with:

var addNestedPropToObj = function (obj, name, value) {
    var path = name.split('.'),
    current = obj,
    len = path.length - 1,
    i = 0;
    for (; i < len; i++) {
        current[path[i]] = current[path[i]] || {};
        current = current[path[i]];
    }
    if ( 0 < path[i].indexOf( "[]" ) ) {
        name = path[i].replace('[]', '');
        current[name] = current[name] || [];
        current[name].push(value);
    } else {
        current[path[i]] = value;
    }
    return obj;
};
jQuery.fn.serializeObject = function () {
    var o = {},
    a = this.serializeArray(),
    i = 0,
    len = a.length;
    for (; i < len; i++) {
        o = addNestedPropToObj(o, a[i].name, a[i].value);
    }
    return o;
};

Demo and test cases

Tips:

  • Always try to separate most of the logic from the plugin into small testable functions.
  • Use a regular loop instead of the $.each().
  • String.prototype.split() returns an array of the entire string if a match isn't found. So the else condition isn't required.

    // not needed
    else {
        o[this.name] = this.value;
    }
    
  • Instead of checking to see if you're at the end of the loop, iterate to path.length - 1 then afterwards perform the statement, current[path[i]] = this.value;.

As for the array format contained within the name property, for simplicity I suggest that the array notation should be an endpoint where the value is the push to the current property. So for a value to a added to an array, then [] must be at the end of the name.

Here's an example:

var func = function( str ){
    return JSON.stringify( addNestedPropToObj( {}, str, 1));
};
func("a[].b") === '{"a[]":{"b":1}}';
func("a.b[]") ===  '{"a":{"b":[1]}}';

Seen as an array: a[] or a.b[]

Seen as a string: a[b], a[b.c]

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.