If I have the following form:
<form>
<input name="foo" value="bar">
<input name="hello" value="world">
<input name="animals[]" value="panda">
<input name="animals[]" value="koala">
<input name="car[make]" value="Honda">
<input name="car[origin]" value="Japan">
</form>
I do not want to use $("form").serialize()
:
foo=bar&hello=world&animals%5B%5D=panda&animals%5B%5D=koalacar&%5Bmake%5D=Honda&car%5Borigin%5D=Japan
Instead, I want this:
{"foo":"bar", "hello":"world", "animals":["panda", "koala"], "car":{"make":"Honda", "origin":"Japan"}}
To my understanding, jQuery used to do this, but they switched the serialize
method to return the GET-style query string. Is there an easy way to get my desired result?
I've updated my original question to include car[make]
and car[origin]
examples. It should be assumed that foo[bar][baz]
or foo[bar][baz][bof]
input could appear on the form as well.
Additionally, numerically indexed keys that are specified such as foo[0]=a
, foo[1]=b
, foo[4]=c
should be preserved, e.g.,
{ ... "foo":["a", "b", undefined, undefined, "c"] ... }
Github: Follow along on Github
The following code can take work with all sorts of input names; and handle them just as you'd expect.
E.g.,
<!-- all of these will work! -->
<input name="honey[badger]" value="a">
<input name="wombat[]" value="b">
<input name="hello[panda][]" value="c">
<input name="animals[0][name]" value="d">
<input name="animals[0][breed]" value="e">
<input name="crazy[1][][wonky]" value="f">
<input name="dream[as][vividly][as][you][can]" value="g">
// output
{
"honey":{
"badger":"a"
},
"wombat":["b"],
"hello":{
"panda":["c"]
},
"animals":[
{
"name":"d",
"breed":"e"
}
],
"crazy":[
null,
[
{"wonky":"f"}
]
],
"dream":{
"as":{
"vividly":{
"as":{
"you":{
"can":"g"
}
}
}
}
}
}
$('#my-form').serializeObject();
(function($){
$.fn.serializeObject = function(){
var self = this,
json = {},
push_counters = {},
patterns = {
"validate": /^[a-zA-Z][a-zA-Z0-9_]*(?:\[(?:\d*|[a-zA-Z0-9_]+)\])*$/,
"key": /[a-zA-Z0-9_]+|(?=\[\])/g,
"push": /^$/,
"fixed": /^\d+$/,
"named": /^[a-zA-Z0-9_]+$/
};
this.build = function(base, key, value){
base[key] = value;
return base;
};
this.push_counter = function(key){
if(push_counters[key] === undefined){
push_counters[key] = 0;
}
return push_counters[key]++;
};
$.each($(this).serializeArray(), function(){
// skip invalid keys
if(!patterns.validate.test(this.name)){
return;
}
var k,
keys = this.name.match(patterns.key),
merge = this.value,
reverse_key = this.name;
while((k = keys.pop()) !== undefined){
// adjust reverse_key
reverse_key = reverse_key.replace(new RegExp("\\[" + k + "\\]$"), '');
// push
if(k.match(patterns.push)){
merge = self.build([], self.push_counter(reverse_key), merge);
}
// fixed
else if(k.match(patterns.fixed)){
merge = self.build([], k, merge);
}
// named
else if(k.match(patterns.named)){
merge = self.build({}, k, merge);
}
}
json = $.extend(true, json, merge);
});
return json;
};
})(jQuery);
You could use ".serializeArray()", and then fix the result:
var json = {};
$.each($('form').serializeArray(), function() {
json[this.name] = this.value;
});
Of course you might want to worry about multi-valued fields:
var json = {};
$.each($('form').serializeArray(), function() {
var cur = json[this.name];
if (cur !== undefined) {
if ($.isArray(cur))
cur.push(this.value);
else
json[ this.name.replace(/\[[^\]]*\]$/, '') ] = [ cur, this.value ];
}
else
json[this.name] = this.value;
});
(edit — now that I think about it, "serialize" and "serializeArray" already kind-of deal with multi-value parameters for you, giving you names like "whatever[2]" in the serialized form. It'd work anyway but it might be unnecessary to do anything more than the simple one.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With