Convert form data to JavaScript object with jQuery
Solution 1
serializeArray already does exactly that. You just need to massage the data into your required format:
function objectifyForm(formArray) {
//serialize data function
var returnArray = {};
for (var i = 0; i < formArray.length; i++){
returnArray[formArray[i]['name']] = formArray[i]['value'];
}
return returnArray;
}
Watch out for hidden fields which have the same name as real inputs as they will get overwritten.
Solution 2
Convert forms to JSON like a boss
The current source is on GitHub and Bower.
$ bower install jquery-serialize-object
The following code is now deprecated.
The following code can take work with all sorts of input names; and handle them just as you'd expect.
For example:
<!-- 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"
}
}
}
}
}
}
Usage
$('#my-form').serializeObject();
The Sorcery (JavaScript)
(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);
Solution 3
What's wrong with:
var data = {};
$(".form-selector").serializeArray().map(function(x){data[x.name] = x.value;});
Solution 4
A fixed version of Tobias Cohen's solution. This one correctly handles falsy values like 0
and ''
.
jQuery.fn.serializeObject = function() {
var arrayData, objectData;
arrayData = this.serializeArray();
objectData = {};
$.each(arrayData, function() {
var value;
if (this.value != null) {
value = this.value;
} else {
value = '';
}
if (objectData[this.name] != null) {
if (!objectData[this.name].push) {
objectData[this.name] = [objectData[this.name]];
}
objectData[this.name].push(value);
} else {
objectData[this.name] = value;
}
});
return objectData;
};
And a CoffeeScript version for your coding convenience:
jQuery.fn.serializeObject = ->
arrayData = @serializeArray()
objectData = {}
$.each arrayData, ->
if @value?
value = @value
else
value = ''
if objectData[@name]?
unless objectData[@name].push
objectData[@name] = [objectData[@name]]
objectData[@name].push value
else
objectData[@name] = value
return objectData
Solution 5
I like using Array.prototype.reduce
because it's a one-liner, and it doesn't rely on Underscore.js or the like:
$('#formid').serializeArray()
.reduce(function(a, x) { a[x.name] = x.value; return a; }, {});
This is similar to the answer using Array.prototype.map
, but you don't need to clutter up your scope with an additional object variable. One-stop shopping.
IMPORTANT NOTE: Forms with inputs that have duplicate name
attributes are valid HTML, and is actually a common approach. Using any of the answers in this thread will be inappropriate in that case (since object keys must be unique).
Yisroel
Updated on October 27, 2021Comments
-
Yisroel over 2 years
How do I convert all elements of my form to a JavaScript object?
I'd like to have some way of automatically building a JavaScript object from my form, without having to loop over each element. I do not want a string, as returned by
$('#formid').serialize();
, nor do I want the map returned by$('#formid').serializeArray();
-
Yisroel almost 15 yearsbecause the first returns a string, exactly like what you'd get if you submitted the form with a GET method, and the second gives you a array of objects, each with a name value pair. I want that if i have a field named "email" i get an object that will allow me to retrieve that value with obj.email. With serializeArray(), i'd have to do something like obj[indexOfElement].value
-
-
Tobias Cohen almost 15 yearsDo you mean "why use serializeArray to get the data in the first place?" Because serializeArray is already written, is unit tested in multiple browsers, and could theoretically be improved in later versions of jQuery. The less code you write that has to access inconsistent things like DOM elements directly, the more stable your code will be.
-
Samuel Meacham almost 14 yearsBe warned, serializeArray() will not include disabled elements. I often disable input elements that are sync'd to other elements on the page, but I still want them included in my serialized object. You're better off using something like
$.map( $("#container :input"), function(n, i) { /* n.name and $(n).val() */ } );
if you need to include disabled elements. -
joshperry over 13 yearsI tried this in a project, using
map
like this creates an array of objects with a single property, it does not collapse the properties all into one object. -
frontendbeauty over 12 yearsSo, that works pretty well. But it's misnamed: it doesn't return JSON, as the name implies. Instead, it returns an object literal. Also, it's important to check for hasOwnProperty, otherwise your arrays have anything that's attached to their prototype, like: {numbers: ["1", "3", indexOf: function(){...}]}
-
maček almost 12 yearsit seems as though you didn't read my entire comment. I devised a solution that handles
foo[bar]
-type inputs as well asfoo[bar][bof][a][b][c][etc]
; see my answer in this thread. Also note thatfoo[bar]
"parsing" is not unique to PHP. Rails heavily relies on this convention for passing form attributes to objects. -
Andrew Barber over 11 yearsStack Overflow isn't here for you to promote your library.
-
pocesar over 11 yearsok but the the
serializeForm
is part of my library and does exactly what the OP wants -
Mulan about 11 yearsIt is risky to
eval
user input - anything could happen. I strongly recommend to not do this. -
Carlo Moretti over 10 yearswhat are you trying to do?
-
Chris Baker over 10 yearsI used a variation of this for a very specific implementation, thanks a lot!
-
Șerban Ghiță over 10 yearsThanks for letting me know that it's useful. I have some incoming features to roll and this motivates me.
-
sites almost 9 years
$(this).serializeArray().reduce(function(m,o){ m[o.name] = o.value; return m;}, {})
-
Alf Eaton about 8 yearsThis does seem to work nicely. There's an alternative repository for jquery-deparam that includes description files for bower and npm.
-
davidtgq almost 8 yearsFrom what I can tell, the difference is that your solution does not depend on
serializeArray
so you have the freedom to choose whatever inputs you want (eg. you can include disabled inputs), right? I.e. this is not coupled to any form or the submit event, it's just independent by itself? -
davidtgq almost 8 yearsCouldn't you get around XSS attacks by converting them to JS object first, instead of directly to string?
-
sites almost 8 yearsthe only small difference with linked answer is that there is no data needed to instantiate,
reduce
returns the object. This is not independent sincetoArray
is from jQuery. -
supertrue about 7 yearsI like this solution, but it doesn't handle form fields in
key[]
array format;[ {key: 'items[]', value: 1 }, {key: 'items[]', value: 2 } ]
results in{ items: { "": 2 } }
. -
Alex78191 almost 7 yearsThe last string is the best
-
Leonardo Beal about 6 yearsThis answer does cover the case mentioned, but it does not cover cases like checkbox[] or even one[another][another_one]
-
Bhavik Hirani about 6 years@LeonardoBeal i fix my ans .. check this now ..!
-
Adarsha about 6 yearsThank you.. this makes (as you mentioned) tiny but very important difference.
-
Jack G almost 5 yearsI am the downvoter and I downvoted because
eval
should not be used in this way becauseeval
, when used in this way, promotes terribly unreliable, buggy, illperformant, and potentially unsecure practices. -
iRaS over 4 yearsI can't agree this is a good answer. And please when you write answers make your code self-explanatory or explain it.
this.c = function(k,v){ eval("c = typeof "+k+";"); if(c == 'undefined') _t.b(k,v);}
is short und not explanatory. A dev with less experience will just copy this without understanding why and how it works. -
Paflow about 4 yearsI get wrong result if I don't add a init-object to that function: $('form').serializeArray().reduce((o, p) => ({...o, [p.name]: p.value}), {})
-
Bhavik Hirani almost 4 years@JackGiffin Check out my new code now because I've removed
eval()
from my code. -
Burhan Kashour almost 3 years@BhavikHirani After a long search, I found your answer, you saved me a long hours of search! thanks man!!
-
Bhavik Hirani almost 3 years@BurhanKashour welcome anytime please don't forget to upvote !
-
Nathan Chappell over 2 years
$(this).serializeArray().reduce((o,kv) => ({...o, [kv.name]: kv.value}), {})
-
skilleo over 2 yearsdoesn't handle nested form notation into json.
-
aret over 2 yearsObviously as it is not considered as valid html html.spec.whatwg.org/multipage/forms.html#the-form-element, even chromium remove nested form
-
chichilatte over 2 yearsPerfect answer.
-
rahman over 2 yearsThank you So Much😍, work for flat Model
-
alex over 2 yearsthis is the one row solution, though others work too.
-
Nidecker over 2 yearsYes! So many upvoted answers, but only this one works properly with checkboxes. Thanks
-
Adam F almost 2 yearsYou mean other than the fact that this doesn't support form arrays?
-
Aldis almost 2 yearsI am not certain how it worked previously, but now it does not. Changed a bit that works:
Object.fromEntries(_.map($('#myform').serializeArray(), _.values))