Problem
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;
};
Solution
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;
};
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]