Reputation: 149
Anyone know of a good way to convert a JSON object to nested form fields.
For example: consider a JSON object:
{'a':{'b':{'c':'1200'}}}, 'z':'foo', 'bar':{'baz':'1', 'id':2}}
I should get:
{'a[b][c]':'1200', 'z':'foo', 'bar[baz]':'1', 'bar[id]':2};
Any ideas?
I am currently using jquery and it feels like something like this already exists, if not I can simply roll my own with a crazy algorithm, but I'd rather use something with a proven track record.
Upvotes: 2
Views: 2880
Reputation: 3042
I would actually recommend a function that takes a nested JSON object and turns it into a HTTP POST string. jQuery will accept that for all of its arguments that require HTTP parameters.
I have written and used the function below in several production apps (use at your own risk):
$.httpSerialize = function(items, parentName) {
var serializedItems = [], serialize = arguments.callee, encodeItem = function(key, value) {
if (value === null || typeof value == 'undefined') return value;
if (value.constructor == Array) {return serialize(value, key);}
return (value.constructor == Object)
? serialize(value, key)
: (value === true || value === false)
? key+"="+new Number(value)
: key+"="+encodeURIComponent(value);
};
if (items.constructor == Array) {
parentName = parentName || 'item';
for (var i = 0; i < items.length; i++) {
var key = parentName+'['+i+']', value = items[i];
serializedItems.push(encodeItem(key, value));
}
} else {
parentName = parentName || '';
for (var key in items) {
var value = items[key];
if (parentName) {
serializedItems.push(encodeItem(parentName+'['+encodeURIComponent(key)+']', value));
} else {
serializedItems.push(encodeItem(encodeURIComponent(key), value));
}
}
}
return serializedItems.join("&");
};
Upvotes: 0
Reputation: 3253
obj = {'a':{'b':{'c':'1200'}}}, 'z':'foo', 'bar':{'baz':'1', 'id':2}}
is internally equivalent to
{['a']['b']['c']:'1200', ['z']:'foo', ['bar']['baz']:'1', ['bar']['id']:2}
Please note that this is not JSON object anymore.
You already can refer first object properties in this way:
var z = obj['a']['b']['c'] // 1200
Is it enough for your needs? Do you really want to convert property names to variables?
Upvotes: 1
Reputation: 58931
So, I have no clue why you want to do what you say you want to do, and I hope you will fill us all in, but this code should be close enough for you to be able to tweak it (this is based on some code of mine that I use to find differences in JavaScript object graphs):
function doStrangeThing(obj) {
var propertyChanges = [];
var objectGraphPath = [];
(function(obj, refObj) {
if ( obj.constructor == Object || (obj.constructor != Number &&
obj.constructor != String && obj.constructor != Date && obj.constructor != Boolean &&
obj.constructor != RegExp && obj.constructor != Function)) {
for (var property in obj) {
objectGraphPath.push((objectGraphPath.length > 0) ? "[" + property + "]" : property);
if (obj[property].constructor != Function) {
if (!refObj[property]) refObj[property] = {};
arguments.callee(obj[property], refObj[property]);
}
objectGraphPath.pop();
}
} else if (obj.constructor != Function) {
if (obj != refObj) {
propertyChanges.push("\"" + objectGraphPath.join("") + "\":\"" + obj.toString() + "\"");
}
}
})(obj, {});
return "{" + propertyChanges.join(",") + "}";
}
Here is what I did to test it:
doStrangeThing({'a':{'b':{'c':'1200'}}, 'z':'foo', 'bar':{'baz':'1', 'id':2}});
Which results in this value:
{"a[b][c]":"1200","z":"foo","bar[baz]":"1","bar[id]":"2"}
Hope that is useful to you in some way...
Upvotes: 3