1681

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();

mruanova
  • 4,119
  • 3
  • 30
  • 46
Yisroel
  • 8,144
  • 4
  • 24
  • 26
  • I'm not understanding why either of those methods are sufficient for your needs? – meder omuraliev Jul 26 '09 at 13:43
  • 16
    because 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 – Yisroel Jul 26 '09 at 14:05
  • This question has a better solution: http://stackoverflow.com/questions/191881/serializing-to-json-in-jquery – Taylor Leese Apr 17 '10 at 16:12
  • 1
    @Taylor I don't see any answer on there that addresses the specific question better than Tobias' answer below. – James McCormack Dec 22 '10 at 12:41
  • 2
    @James - The accepted answer using D. Crockford's JSON-js library. Here's an example: https://github.com/tleese22/google-app-engine-jappstart/blob/master/src/main/webapp/js/script.js – Taylor Leese Dec 22 '10 at 20:11
  • 4
    @Taylor Yes, I'd say the correct answer uses Crockford's lib and Tobias' function like so: JSON.stringify($('myForm').serializeObject()) – James McCormack Dec 23 '10 at 12:30
  • 1
    VOTE 100! Enjoy your badge :) – maček Dec 06 '11 at 21:55
  • All of the below methods are insane, just use $.serialize, it is transmitted just as well in a POST as in a GET. – Jon z May 21 '12 at 16:12
  • 5
    @Jonz - There are other reasons besides submission/transmission for using a form element. If you're doing any heavy lifting with the form values within JavaScript (e.g. single page app), it's very handy to have them in an object format for accessing & manipulating. Also, HTTP Post and Get query strings aren't the only formats for moving data around. – Patrick M Jul 09 '12 at 14:11
  • 3
    A good js I came across >> https://github.com/marioizquierdo/jquery.serializeJSON – Bongs Mar 02 '13 at 21:56
  • @TaylorLeese the link in your comment is now a 404. – Boggin Aug 05 '15 at 14:26
  • @Yisroel It's possible, but it will fail for forms that have multiple inputs with the same name value (e.g. `name="foo[]"`). Both .serialize() and .serializeArray() handle that case. I'm assuming your specific use case doesn't use that pattern. – Erics Jan 12 '17 at 00:17
  • 1
    check this https://stackoverflow.com/a/39248551/6293856 – Bhavik Hirani Feb 27 '18 at 19:32
  • If you are trying to convert all form fields to JSON in order to submit this form through Ajax here is [a jQuery form plugin](http://malsup.com/jquery/form/) that does that. – serg Jul 26 '09 at 17:01
  • [`$('#formid').serializeArray().reduce((o,p) => ({...o, [p.name]: p.value}))`](https://stackoverflow.com/a/59145232/405550) – Zaz Dec 02 '19 at 19:09

54 Answers54

1689

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.

Ruben Helsloot
  • 10,555
  • 5
  • 17
  • 36
Tobias Cohen
  • 19,480
  • 7
  • 51
  • 51
  • 4
    as tvanfosson says, why iterate over the collection twice? – Yisroel Jul 27 '09 at 16:15
  • 70
    Do 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. – Tobias Cohen Jul 28 '09 at 03:05
  • 1
    Thanks Tobias, was looking for a best practice. – Matt Gardner Aug 18 '09 at 21:52
  • 58
    Be 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. – Samuel Meacham Jul 18 '10 at 23:54
  • I think you need to add this to your code just after each statement:
    this.name=this.name.replace('[]','');
    if not, then there would be error in parsing JSON.
    – Morteza Milani Sep 15 '10 at 01:26
  • 1
    serializeObject() is half the solution - the other half is the Crockford JSON lib. Full solution is therefore: JSON.stringify($('myForm').serializeObject()) – James McCormack Dec 23 '10 at 12:32
  • Samuel Meacham, you may want to use readonly elements instead of disabled ones. – Andrew B. Feb 22 '11 at 05:04
  • The $.toJson in your referenced example does not exist (any more). Also even in your sample the inner expression does not catch all form elements (e.g. checkboxes status, ...). – Frank Nocke Apr 05 '11 at 10:22
  • This solution contains a bug where "falsy" values such as 0, '', and false won't be serialized correctly. I have posted a fixed solution. – Daniel X Moore Apr 06 '11 at 20:06
  • 1
    Plugin by Ben Alman can also be used: http://benalman.com/projects/jquery-misc-plugins/#serializeobject – Shamaila Tahir Oct 02 '11 at 09:11
  • 2
    This doesn't work for general case. It produce invalid results for name="model[property_name]". It also doesn't handle nested properties. name="model[prop_1][prop_2]". So it should not considered as answer. – Alexey Zakharov Oct 26 '11 at 07:30
  • 1
    This is so rigid, it's mind-blowing that it ever received more than a couple upvotes. – maček Dec 06 '11 at 21:57
  • @macek Is there something specific about it that you've found problematic? I wrote this code in about 5 minutes to answer the question as asked, and it seems to have worked fine for the OP, as well as for many others. – Tobias Cohen Dec 07 '11 at 04:33
  • 24
    @TobiasCohen It doesn't handle `foo[bar]`-type inputs as expected, not to mention most of the other input name varieties. After being very frustrated with shallow solutions to this problem, I ended up writing my own jQuery plugin -- details in the answer I provided to this question. – maček Dec 07 '11 at 20:13
  • 3
    @macek I think you might be looking for an answer to a different question. `foo[bar]` style input naming is common convention in a number of web frameworks, but it's certainly not a standard part of HTML forms, it's not mentioned in the question, and I've made no attempt to deal with it here. – Tobias Cohen Dec 08 '11 at 00:47
  • @macek The foo[bar] type input is a PHP only parsing thing, but I too find it very useful. Using Tobias's great solution above, I modified it to correctly handle the foo[bar] case. I just whipped this up in about 5 minutes so I'm sure it can be made a lot neater. Okay, it seems I can't post it in a comment, so see my answer below – Kevin Jhangiani May 19 '12 at 06:19
  • 2
    @TobiasCohen, I understand not wanting to support it, but saying it's "not a standard part of HTML forms" is neither correct or a valid counter point. An input named `foo[bar]` is certainly valid; atop that, adding support for the intended functionality results in a more robust and flexible solution. – maček May 22 '12 at 03:35
  • 2
    @macek Could you show me where in the HTML spec it says that inputs named in this format should be treated specially? – Tobias Cohen May 22 '12 at 07:44
  • 3
    @TobiasCohen, I never said the HTML spec says they should be treated specially. I was simply arguing that `foo[bar]`-type names are completely valid and `[]` is commonly understood to be an array accessor; why not handle them as such? Or to pose it a bit differently, in what scenario would you name an input `foo[bar]` and not wish to treat `foo` as an array? – maček May 22 '12 at 18:34
  • 6
    @macek I know this is a few months old, but since when did do arrays use non-numeric indexes? No one should name an input foo[bar] and hope to treat it as an array. Are you confusing arrays and hashes? Yes, [] is commonly understood to be an accessor but not just for arrays. Also saying it's valid HTML but not in the HTML spec is a contradiction. Yes, the browser may not choke on it, but not many webservers are going to know how to deserialize that like they would an array. Why? Because its not in the HTML spec. Therefore, it is indeed invalid. – kroehre Sep 08 '12 at 08:29
  • This is great but it doesn't parse data types. It makes all the values strings. Maybe that should be handled elsewhere but it's a caveat to this snippet. Still, amazingly useful for how simple it is. Thanks! – Tony R Jan 15 '13 at 20:40
  • @Samuel Meacham, I believe you should be using the `readonly` attribute, not `disabled`, if you want to include the inputs on the form submission/serialization. – nilskp Feb 13 '13 at 14:44
  • 2
    jQuery itself should provide this function in most recent next version, don't you think so? – destan Apr 04 '13 at 11:39
  • treats a select with only one option selected as a string. where there is potential for mulitple options and only one is selected, it should be treated as an array. i'm working on something to remedy this. – dewd May 28 '13 at 14:53
  • 3
    The jQuery plugin serializeJSON uses serailizeArray under the hood to serialize complex forms into the same format as Rails params: https://github.com/marioizquierdo/jquery.serializeJSON – tothemario Jan 08 '14 at 03:03
  • change:case 'checkbox': if (val === 'on' || val === 'checked' || val === true || val === 1) $el.attr('checked', 'checked'); else $el.attr('checked', null); – H.M. Apr 21 '14 at 15:19
  • Would like to suggest this improvement: http://jsfiddle.net/S9MY8/1/ The difference is it handles keys in the input name, e.g. name="test[1]" and preserves these in an object. so rather than: "test[]" : ['val1','val2'] you would have: "test" : { 1 : 'val1', 2 : 'val2' } This worked better for my purposes anyway, passing form values into an underscore template. – Aaron Lozier Jun 22 '14 at 19:01
  • Shouldn't this code be added to jQuery? It really needs to be implemented. – Gustavo Gondim Jul 14 '14 at 13:52
  • I use this function all the time and it works fantastic. Just wanted to counterpoint all the negative feedback. No bulky plugins, works fast and reliably. Support VALID html so that's all I needed. – ladieu Jul 17 '14 at 14:19
  • @TobiasCohen, I know this is quite an old thread, but I updated you function to serialize disabled fields as well. Hope it helps! – victor Dec 30 '14 at 14:34
  • @TobiasCohen and for files the type="file". Is it possible? – jcarlosweb Jan 31 '15 at 20:10
  • @TobiasCohen - I think Ben Alman provides a better solution: http://benalman.com/projects/jquery-misc-plugins/#serializeobject. You also use `o[this.name]` in multiple places, and that should be cached for faster performance: `var oname = o[this.name];` – tim-montague May 30 '15 at 18:03
  • If you use jquery to post this object to the server, and you have a multiple select on your form, and the name of your control is 'foo', then jquery will send 'foo' if only one item is selected and 'foo[]' if multiple items are selected. This will be very confusing on the server side. – nima Jul 29 '15 at 22:10
  • better than the alternative than to massage an array into a JSON object using string manipulations – Eon Jul 19 '16 at 14:15
  • 2
    From http://css-tricks.com/snippets/jquery/serialize-form-to-json/ Excellent snippet – Andrew Day Jan 18 '17 at 14:36
  • Does anyone know if this is still maintained? Should I avoid using it??? – clod986 Jun 29 '17 at 17:04
  • 1
    Modern version of the above: `form.serializeArray().reduce(function(acc,cur) { acc[cur.name] = cur.value return acc }, {})` – conny Sep 08 '17 at 09:46
  • const data = $(form).serializeArray().reduce((acc, next) => ({ ...acc, [next.name]: next.value }), {}) – cstuncsik Feb 16 '18 at 08:48
  • 1
    @conny, your modern version gives me the error "unexpected token: keyword 'return'" – Paul Chris Jones Oct 04 '19 at 11:02
  • @PaulJones you are correct, it must have been due to some copy paste mistake on my side. `form.serializeArray().reduce(function(acc,cur) { acc[cur.name] = cur.value ; return acc }, {})` should do the job (missing `;`). – conny Oct 17 '19 at 09:41
  • is there a full proof solution? none of the answers handles all the scenarios. like arrays, deep hierarchy. – LP13 May 15 '20 at 21:52
  • this works like a charm, although it overrides checkbox values with the same name. If for example you have multiple checkboxes with the same name and two or more are checked, only the last value will be taken – Jonas Merhej Mar 17 '21 at 04:41
459

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);
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
maček
  • 69,649
  • 33
  • 159
  • 193
  • 17
    So, 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(){...}]} – frontendbeauty Dec 29 '11 at 00:44
  • 1
    @frontendbeauty It would be very cool if you be a little more explicit or even do a pull request on Github for this (I'm not sure what you mean with the `hasOwnProperty` remark) – julien_c Mar 13 '12 at 17:07
  • @julien_c re: `hasOwnProperty`, check out the docs on [MDN](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/HasOwnProperty) – frontendbeauty Mar 14 '12 at 20:45
  • 5
    @frontendbeauty actually, toJSON is exactly what the spec says it should be called: https://developer.mozilla.org/en/JSON#toJSON()_method an unfortunate misnomer. – Ryan Florence May 23 '12 at 17:21
  • @frontendbeauty, I never understood your comment. This is using jQuery's `.serializeArray()` so it's just constructing a new object with `key/value` pairs; nothing else. – maček Dec 20 '12 at 19:27
  • Unfortunately it doesn't work well for – Marek Jan 31 '13 at 13:03
  • 4
    @Marek, I did a test for here on [jsfiddle](http://jsfiddle.net/y8MPQ/1/). The trick is to name your select properly. ``, it will work just fine :) – maček Jan 31 '13 at 18:14
  • Hi, I made a fiddle using select boxes and can't get this to work - http://jsfiddle.net/QqT2w/1/ – rix Sep 05 '13 at 13:15
  • @rix it does not work because jsfiddle refuses to load jquery plugin due to "its MIME type ('text/plain') is not executable, and strict MIME type checking is enabled" I have copied the JS source of jquery plugin which is above in this answer. here is updated demo: http://jsfiddle.net/ihusnjak/QqT2w/2/ – Ivan Hušnjak Sep 06 '13 at 22:31
  • I didn't realize he left a comment on this answer too. Anyone following @rix's (invalid) bug, please see the [github issue](https://github.com/macek/jquery-serialize-object/issues/8) – maček Sep 09 '13 at 03:15
  • 3
    Wanted to point out that https://github.com/serbanghita/formToObject is a similar JavaScript method (no 3rd party libraries needed) that does the same job. Supports 'multiple', ignores 'disabled' elements. – Șerban Ghiță Sep 26 '13 at 22:22
  • 8
    This solution should be on top as it deals with the problem of nested keys as form element names. – SquareCat Feb 23 '14 at 00:34
  • 2
    I agree that this is the more robust solution. If you have more than just a flat set of data you will need this solution. In my case, I have arrays of sub types (e.g. Reservations have an array of Payments). This solutions returned an array of subdocuments called Payments with each payment attribute. Love it! – Michael Moser Mar 06 '14 at 22:42
  • 1
    Today i had a problem with multiple-select fields. If they were empty (=no selection) no value would get sent to the server (**this is correct behaviour!**), thus the server would not recognize that the selection was (more or less) reset to nothing. So if anyone runs into this problem: i solved it by adding a hidden form field before each multiple-select, with the same name. Therefore if no value is selected in the multiple-select, an empty value with the same form field name is sent to the server and there you can deal with the thing accordingly. – SquareCat Mar 09 '14 at 23:00
  • I ran into another issue with the function today. I think that i may have found a leak. Author, could you please explain why: http://jsfiddle.net/VX9RW/1/ happens? – SquareCat Mar 25 '14 at 22:00
  • @SquareCat, If you're referring to the `[null,null,...,null,1]`, this is not a leak. [Please see this issue](https://github.com/macek/jquery-serialize-object/issues/18). Also, please update the version of the plugin you're using. I can only afford to support the current version. – maček Mar 25 '14 at 23:45
  • How can I use brackets for arrays and dots for properties? Example of form names: needs to become: {people:[{'first':'Bill','last':'Henderson'},{'first':'Jane','last':'Henderson'}]}...This is the way the default model binder in mvc works (and the output is nice and transparent too). – BlackjacketMack Sep 24 '15 at 12:54
  • @BlackjacketMack all support for this project has moved to Github. Please read the [readme](https://github.com/macek/jquery-serialize-object). – maček Sep 28 '15 at 04:52
  • 2
    thank you so much. best solution what i have ever seen for multidimensional forms! – LINKeRxUA Dec 23 '15 at 06:51
  • @frontendbeauty, it doesn't return an object literal. That's misunderstanding the concept of a literal. It just returns an object. – GetFree Aug 04 '16 at 08:55
  • I have this input: Natively, in PHP I see: "vehicle" => array:6 [▼ 0 => "0" 1 => "1" 2 => "5" 3 => "4" 4 => "6" "rt" => "7" ] Use AJAX and your method, in PHP I see: "vehicle" => array:1 [ "rt" => "7" ] Behavior is not same, specific to PHP? – Thomas Cheng Aug 11 '16 at 19:16
  • 3
    Please explain what "The following code is now deprecated." means. In favor of what? – Ultimater Nov 01 '18 at 04:34
  • Yes, if this is deprecated what is the preferred solution? – Codewise Mar 16 '19 at 15:31
  • I dont know why this answer is not on the top. Works like a champ. – Tushar Saxena Oct 24 '19 at 08:48
  • This solution does not work. if you have `input` elements named, for example,`World.Countries[0]`, `World.Countries[1]`,`World.Countries[2]`,`World.Countries[3]` then it does not create proper object – LP13 May 16 '20 at 06:36
  • Tip to fix: Using dash "-" as part of field name your function will fail, try use fe. – drozdo Mar 10 '21 at 13:06
291

What's wrong with:

var data = {};
$(".form-selector").serializeArray().map(function(x){data[x.name] = x.value;}); 
mkschreder
  • 267
  • 1
  • 7
  • 14
  • 1
    Very simple and effective, but how do you make it account for radio groups where no radio is selected? – Lars Gyrup Brink Nielsen Nov 25 '13 at 07:10
  • 2
    @LayZee - if nothing is selected, why would you want it on your back end? if you must select an option, validate the input before serializing. – Rafael Herscovici Sep 30 '14 at 15:24
  • 22
    if you're not returning anything, why don't you just use `.each` instead of `.map` ?? – azerafati Nov 06 '14 at 10:14
  • 11
    It's so simple because it's super naive... doesn't handle checkboxes with same name. Each time it will override checked item before it. You'll definitely need some input type detection to ensure it's properly serialized. – Joshua F. Rountree Apr 08 '15 at 14:35
  • 5
    If you want a pure jQuery solution, you could use `var form = {}; $.each($(this).serializeArray(), function (i, field) { form[field.name] = field.value || ""; });` – tim-montague May 31 '15 at 07:02
  • 45
    `$(this).serializeArray().reduce(function(m,o){ m[o.name] = o.value; return m;}, {})` – sites Jun 13 '15 at 21:19
  • In the case of a multiple select input, this only returns the last value. – nima Jul 29 '15 at 18:35
  • @JoshuaRountree I would disagree regarding "type detection" not necessary at all, `.serializeArray()` should handle the types like checkbox multiple (for select) etc... values are already what they are, this is simple case of flattening the object. – Val Oct 19 '15 at 15:23
  • and what about `$($("form").find(":input").serializeArray()).each(function(k,v) { form[v.name] = v.value})` – jneira Feb 25 '16 at 13:45
  • Awesome! Super simple! – samurai jack Dec 14 '16 at 04:24
  • 2
    This really is the simplest way to flatten the array to a key->value hash. Of course, there's no need for map since you're not over-writing the original array, just use `forEach`. Like this: `var data = {}; $(".form-selector").serializeArray().forEach(function(x){data[x.name] = x.value;});` Simple, complete, and effective. – KyleFarris Feb 16 '17 at 18:43
  • when u have multiple checkbox that belong to same field, when u leave all unchecked, u should get empty array – crapthings Apr 14 '17 at 04:33
  • 1
    this doesn't support foo[xxx] = 1, foo[yyy] = 2 you should get: foo: { xxx:1, yyy:2} but in this case you get {foo[xxx]:1, foo[yyy]:2} – anativ Sep 11 '17 at 10:31
  • Works perfectly supported in all the browser as well – raftaar1191 Sep 12 '17 at 21:20
  • $(this).serializeArray().reduce((m,{name, value}) => {m[name] = value; return m}, {}) – Atr0x May 09 '20 at 18:30
103

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
Daniel X Moore
  • 13,409
  • 12
  • 75
  • 88
  • In the coffeescript, that first if block can be shortened to `value = @value ? ''` – nzifnab Sep 10 '12 at 23:23
  • And if you're trying to serialize Rails-like forms, you may want to remove element root from the generated keys. To achieve that, I've added a new param `keyMap` and the following line: `key = if keyMap? then keyMap(@name) else @name`. Now you can pass mapping function like `(name) -> name.match(/\[([^\]]+)]/)[1]`. And then one would need to change all subsequent `@name` to `key`, of course – Damir Zekić Oct 19 '12 at 13:23
  • @DamirZekić, if your root element was `post`, you could simply do `$('form').serializeObject().post`. No need for fancy mapping. – maček Dec 20 '12 at 19:21
  • @DamirZekić What is this line doing? `if (!objectData[this.name].push)`?? – kittu Jun 20 '17 at 18:10
  • @kittu It's checking if `objectData[this.name]` has the push method (roughly, is it an array). If it is an array it pushes the value, if it's not an array it converts it to an array so that multiple values with the same key will be combined to an array. – Daniel X Moore Jun 20 '17 at 22:09
68

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).

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Ethan Brown
  • 24,393
  • 2
  • 71
  • 89
  • This is quite elegant. But it's worth noting that `array.prototype.reduce()` is not available in IE8 as it is part of the ECMAScript 5 specification. So if you need IE8 support, you'll want to use a [polyfill](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce#Polyfill) or another solution altogether. – gfullam Mar 12 '15 at 14:02
  • 3
    True, but it's easy enough to polyfill. Also, the IE8 headache is *almost* over, thanks to Microsoft's great work with IE11 Enterprise Mode -- I no longer cater to individual users with IE8, but when an organization with 10,000 employees that all use IE8 comes along...that's different. Fortunately, Microsoft is working hard on that problem. – Ethan Brown Mar 12 '15 at 15:16
  • 1
    Well you should have your IT folks look into IE11 Enterprise mode -- it provides a modern browser AND a way to run IE8-compatible apps. Smart move on Microsoft's part: http://www.howtogeek.com/184634/how-to-enable-and-use-internet-explorer-11s-enterprise-mode/ – Ethan Brown Mar 12 '15 at 15:19
29

All of these answers seemed so over the top to me. There's something to be said for simplicity. As long as all your form inputs have the name attribute set this should work just jim dandy.

$('form.myform').submit(function () {
  var $this = $(this)
    , viewArr = $this.serializeArray()
    , view = {};

  for (var i in viewArr) {
    view[viewArr[i].name] = viewArr[i].value;
  }

  //Do stuff with view object here (e.g. JSON.stringify?)
});
24

There really is no way to do this without examining each of the elements. What you really want to know is "has someone else already written a method that converts a form to a JSON object?" Something like the following should work -- note that it will only give you the form elements that would be returned via a POST (must have a name). This is not tested.

function formToJSON( selector )
{
     var form = {};
     $(selector).find(':input[name]:enabled').each( function() {
         var self = $(this);
         var name = self.attr('name');
         if (form[name]) {
            form[name] = form[name] + ',' + self.val();
         }
         else {
            form[name] = self.val();
         }
     });

     return form;
}
tvanfosson
  • 490,224
  • 93
  • 683
  • 780
  • true, i'd love a plugin that would do this for me. the limitation of having a name is no big deal. will this pull all fields in a form, including textareas and selects? – Yisroel Jul 26 '09 at 14:02
  • not sure if you want to account for [disabled] but I don't think that should be sent/picked up. – meder omuraliev Jul 26 '09 at 14:06
  • might be simpler to use serializeArray() to get the map, and then use code similar to the above to convert it a normal JSON object, this way i'm not dealing with the form itself – Yisroel Jul 26 '09 at 14:10
  • 2
    Using the serializedArray would work, but essentially you'd be iterating over the collection twice -- once to produce the array, then over the array. I don't see the need for that. – tvanfosson Jul 26 '09 at 14:50
  • I'll adjust the selector for enabled/disabled. – tvanfosson Jul 26 '09 at 14:51
  • Works good for me, except for radio buttons - so I added another if and now works fine. Thanks – Martin Lazar Jan 25 '11 at 14:00
  • You should use arrays to store the field values rather than appending strings with commas so that fields which contain commas can be parsed properly. – Daniel X Moore Jul 12 '11 at 10:26
24

[UPDATE 2020]

With a simple oneliner in vanilla js that leverages fromEntries (as always, check browser support):

Object.fromEntries(new FormData(form))
Jeromy French
  • 11,372
  • 13
  • 67
  • 119
aret
  • 86
  • 1
  • 6
  • 1
    This is a great (and the simplest) implementation, the only caveat being that it requires a fairly up-to date web browser. For example, this is supported from Google Chrome 73 and Safari 12.1 where both were released in March 2019; and Opera 60 which was released in April 2019. – aullah Oct 01 '20 at 19:31
  • This currently (Feb 2021) is well enough supported, to call it the solution. – theking2 Feb 25 '21 at 10:10
21

If you are using Underscore.js you can use the relatively concise:

_.object(_.map($('#myform').serializeArray(), _.values))
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
olleicua
  • 1,717
  • 1
  • 17
  • 30
20

I checked that there is a problem with all the other answers, that if the input name is as an array, such as name[key], then it should be generated like this:

name:{ key : value }


For example: If you have an HTML form similar to the one below:

<form>
    <input name="name" value="value" >
    <input name="name1[key1]" value="value1" >
    <input name="name2[key2]" value="value2" >
    <input name="name3[key3]" value="value3" >
</form>

But it should be generated just like the JSON below, and does not become an object like the following with all the other answers. So if anyone wants to bring something like the following JSON, try the JS code below.

{
    name  : 'value',
    name1 : { key1 : 'value1' },
    name2 : { key2 : 'value2' },
    name3 : { key2 : 'value2' }
}

$.fn.getForm2obj = function() {
  var _ = {};
  $.map(this.serializeArray(), function(n) {
    const keys = n.name.match(/[a-zA-Z0-9_]+|(?=\[\])/g);
    if (keys.length > 1) {
      let tmp = _;
      pop = keys.pop();
      for (let i = 0; i < keys.length, j = keys[i]; i++) {
        tmp[j] = (!tmp[j] ? (pop == '') ? [] : {} : tmp[j]), tmp = tmp[j];
      }
      if (pop == '') tmp = (!Array.isArray(tmp) ? [] : tmp), tmp.push(n.value);
      else tmp[pop] = n.value;
    } else _[keys.pop()] = n.value;
  });
  return _;
}
console.log($('form').getForm2obj());
$('form input').change(function() {
  console.clear();
  console.log($('form').getForm2obj());
});
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<form>
  <input name="name" value="value">
  <input type="checkbox" name="name1[]" value="1" checked="checked">1
  <input type="checkbox" name="name1[]" value="2">2
  <input type="checkbox" name="name1[]" value="3">3<br>
  <input type="radio" name="gender" value="male" checked="checked">male
  <input type="radio" name="gender" value="female"> female
  <input name="name2[key1]" value="value1">
  <input name="one[another][another_one]" value="value4">
  <input name="name3[1][name]" value="value4">
  <input name="name3[2][name]" value="value4">
  <input name="[]" value="value5">
</form>
Bhavik Hirani
  • 1,764
  • 4
  • 24
  • 38
  • This answer does cover the case mentioned, but it does not cover cases like checkbox[] or even one[another][another_one] – Leonardo Beal Feb 14 '18 at 16:06
  • 1
    @LeonardoBeal i fix my ans .. check this now ..! – Bhavik Hirani Feb 27 '18 at 19:30
  • I am the downvoter and I downvoted because `eval` should not be used in this way because `eval`, when used in this way, promotes terribly unreliable, buggy, illperformant, and potentially unsecure practices. – Jack Giffin Jul 31 '19 at 21:04
  • 2
    I 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. – iRaS Nov 27 '19 at 09:11
  • 2
    @JackGiffin Check out my new code now because I've removed `eval()` from my code. – Bhavik Hirani May 25 '20 at 17:02
  • @BhavikHirani Thank you for removing useless uses of eval. I have changed my downvote into an upvote. – Jack Giffin May 25 '20 at 20:38
19

Ok, I know this already has a highly upvoted answer, but another similar question was asked recently, and I was directed to this question as well. I'd like to offer my solution as well, because it offers an advantage over the accepted solution: You can include disabled form elements (which is sometimes important, depending on how your UI functions)

Here is my answer from the other SO question:

Initially, we were using jQuery's serializeArray() method, but that does not include form elements that are disabled. We will often disable form elements that are "sync'd" to other sources on the page, but we still need to include the data in our serialized object. So serializeArray() is out. We used the :input selector to get all input elements (both enabled and disabled) in a given container, and then $.map() to create our object.

var inputs = $("#container :input");
var obj = $.map(inputs, function(n, i)
{
    var o = {};
    o[n.name] = $(n).val();
    return o;
});
console.log(obj);

Note that for this to work, each of your inputs will need a name attribute, which will be the name of the property of the resulting object.

That is actually slightly modified from what we used. We needed to create an object that was structured as a .NET IDictionary, so we used this: (I provide it here in case it's useful)

var obj = $.map(inputs, function(n, i)
{
    return { Key: n.name, Value: $(n).val() };
});
console.log(obj);

I like both of these solutions, because they are simple uses of the $.map() function, and you have complete control over your selector (so, which elements you end up including in your resulting object). Also, no extra plugin required. Plain old jQuery.

Community
  • 1
  • 1
Samuel Meacham
  • 9,845
  • 7
  • 42
  • 50
  • 6
    I 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. – joshperry Oct 01 '10 at 22:46
15

This function should handle multidimensional arrays along with multiple elements with the same name.

I've been using it for a couple years so far:

jQuery.fn.serializeJSON=function() {
  var json = {};
  jQuery.map(jQuery(this).serializeArray(), function(n, i) {
    var _ = n.name.indexOf('[');
    if (_ > -1) {
      var o = json;
      _name = n.name.replace(/\]/gi, '').split('[');
      for (var i=0, len=_name.length; i<len; i++) {
        if (i == len-1) {
          if (o[_name[i]]) {
            if (typeof o[_name[i]] == 'string') {
              o[_name[i]] = [o[_name[i]]];
            }
            o[_name[i]].push(n.value);
          }
          else o[_name[i]] = n.value || '';
        }
        else o = o[_name[i]] = o[_name[i]] || {};
      }
    }
    else {
      if (json[n.name] !== undefined) {
        if (!json[n.name].push) {
          json[n.name] = [json[n.name]];
        }
        json[n.name].push(n.value || '');
      }
      else json[n.name] = n.value || '';      
    }
  });
  return json;
};
the Tin Man
  • 150,910
  • 39
  • 198
  • 279
14

You can do this:

var frm = $(document.myform);
var data = JSON.stringify(frm.serializeArray());

See JSON.

Andrew
  • 13,934
  • 8
  • 78
  • 93
Harini Sekar
  • 630
  • 7
  • 14
13

One-liner (no dependencies other than jQuery), uses fixed object binding for function passsed to map method.

$('form').serializeArray().map(function(x){this[x.name] = x.value; return this;}.bind({}))[0]

What it does?

"id=2&value=1&comment=ok" => Object { id: "2", value: "1", comment: "ok" }

suitable for progressive web apps (one can easily support both regular form submit action as well as ajax requests)

test30
  • 2,920
  • 28
  • 24
11

Use:

function form_to_json (selector) {
  var ary = $(selector).serializeArray();
  var obj = {};
  for (var a = 0; a < ary.length; a++) obj[ary[a].name] = ary[a].value;
  return obj;
}

Output:

{"myfield": "myfield value", "passwordfield": "mypasswordvalue"}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Adrian Seeley
  • 1,902
  • 1
  • 23
  • 35
7

From some older answer:

$('form input, form select').toArray().reduce(function(m,e){m[e.name] = $(e).val(); return m;},{})
sjngm
  • 11,411
  • 13
  • 72
  • 105
sites
  • 19,991
  • 16
  • 81
  • 136
  • From 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 May 27 '16 at 01:12
  • the only small difference with linked answer is that there is no data needed to instantiate, `reduce` returns the object. This is not independent since `toArray` is from jQuery. – sites May 27 '16 at 15:09
6

Simplicity is best here. I've used a simple string replace with a regular expression, and they worked like a charm thus far. I am not a regular expression expert, but I bet you can even populate very complex objects.

var values = $(this).serialize(),
attributes = {};

values.replace(/([^&]+)=([^&]*)/g, function (match, name, value) {
    attributes[name] = value;
});
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
ngr
  • 139
  • 2
  • 10
6

I found a problem with Tobias Cohen's code (I don't have enough points to comment on it directly), which otherwise works for me. If you have two select options with the same name, both with value="", the original code will produce "name":"" instead of "name":["",""]

I think this can fixed by adding " || o[this.name] == ''" to the first if condition:

$.fn.serializeObject = function()
{
    var o = {};
    var a = this.serializeArray();
    $.each(a, function() {
        if (o[this.name] || o[this.name] == '') {
            if (!o[this.name].push) {
                o[this.name] = [o[this.name]];
            }
            o[this.name].push(this.value || '');
        } else {
            o[this.name] = this.value || '';
        }
    });
    return o;
};
user1134789
  • 51
  • 1
  • 2
5

Using maček's solution, I modified it to work with the way ASP.NET MVC handles their nested/complex objects on the same form. All you have to do is modify the validate piece to this:

"validate": /^[a-zA-Z][a-zA-Z0-9_]*((?:\[(?:\d*|[a-zA-Z0-9_]+)\])*(?:\.)[a-zA-Z][a-zA-Z0-9_]*)*$/,

This will match and then correctly map elements with names like:

<input type="text" name="zooName" />

And

<input type="text" name="zooAnimals[0].name" />
Community
  • 1
  • 1
G-Ram
  • 23
  • 3
  • 6
5
const formData = new FormData(form);

let formDataJSON = {};

for (const [key, value] of formData.entries()) {

    formDataJSON[key] = value;
}
Stonetip
  • 1,092
  • 10
  • 20
4

There is a plugin to do just that for jQuery, jquery.serializeJSON. I have used it successfully on a few projects now. It works like a charm.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Michael Yagudaev
  • 5,629
  • 2
  • 43
  • 50
4

the simplest and most accurate way i found for this problem was to use bbq plugin or this one (which is about 0.5K bytes size).

it also works with multi dimensional arrays.

$.fn.serializeObject = function()
{
 return $.deparam(this.serialize());
};
Roey
  • 1,440
  • 19
  • 16
  • This does seem to work nicely. There's [an alternative repository for jquery-deparam](https://github.com/AceMetrix/jquery-deparam) that includes description files for bower and npm. – Alf Eaton Apr 19 '16 at 14:36
4

Another answer

document.addEventListener("DOMContentLoaded", function() {
  setInterval(function() {
    var form = document.getElementById('form') || document.querySelector('form[name="userprofile"]');
    var json = Array.from(new FormData(form)).map(function(e,i) {this[e[0]]=e[1]; return this;}.bind({}))[0];
    
    console.log(json)
    document.querySelector('#asJSON').value = JSON.stringify(json);
  }, 1000);
})
<form name="userprofile" id="form">
  <p>Name <input type="text" name="firstname" value="John"/></p>
  <p>Family name <input name="lastname" value="Smith"/></p>
  <p>Work <input name="employment[name]" value="inc, Inc."/></p>
  <p>Works since <input name="employment[since]" value="2017" /></p>
  <p>Photo <input type="file" /></p>
  <p>Send <input type="submit" /></p>
</form>

JSON: <textarea id="asJSON"></textarea>

FormData: https://developer.mozilla.org/en-US/docs/Web/API/FormData

Jonathan Marzullo
  • 6,451
  • 2
  • 38
  • 45
test30
  • 2,920
  • 28
  • 24
3

I prefer this approach because: you don't have to iterate over 2 collections, you can get at things other than "name" and "value" if you need to, and you can sanitize your values before you store them in the object (if you have default values that you don't wish to store, for example).

$.formObject = function($o) {
    var o = {},
        real_value = function($field) {
            var val = $field.val() || "";

            // additional cleaning here, if needed

            return val;
        };

    if (typeof o != "object") {
        $o = $(o);
    }

    $(":input[name]", $o).each(function(i, field) {
        var $field = $(field),
            name = $field.attr("name"),
            value = real_value($field);

        if (o[name]) {
            if (!$.isArray(o[name])) {
                o[name] = [o[name]];
            }

            o[name].push(value);
        }

        else {
            o[name] = value;
        }
    });

    return o;
}

Use like so:

var obj = $.formObject($("#someForm"));

Only tested in Firefox.

kflorence
  • 1,989
  • 1
  • 15
  • 15
2

I had the same problem lately and came out with this .toJSON jQuery plugin which converts a form into a JSON object with the same structure. This is also expecially useful for dynamically generated forms where you want to let your user add more fields in specific places.

The point is you may actually want to build a form so that it has a structure itself, so let's say you want to make a form where the user inserts his favourite places in town: you can imagine this form to represent a <places>...</places> XML element containing a list of places the user likes thus a list of <place>...</place> elements each one containing for example a <name>...</name> element, a <type>...</type> element and then a list of <activity>...</activity> elements to represent the activities you can perform in such a place. So your XML structure would be like this:

<places>

    <place>

        <name>Home</name>
        <type>dwelling</type>

        <activity>sleep</activity>
        <activity>eat</activity>
        <activity>watch TV</activity>

    </place>

    <place>...</place>

    <place>...</place>

</places>

How cool would it be to have a JSON object out of this which would represent this exact structure so you'll be able to either:

  • Store this object as it is in any CouchDB-like database
  • Read it from your $_POST[] server side and retrive a correctly nested array you can then semantically manipulate
  • Use some server-side script to convert it into a well-formed XML file (even if you don't know its exact structure a-priori)
  • Just somehow use it as it is in any Node.js-like server script

OK, so now we need to think how a form can represent an XML file.

Of course the <form> tag is the root, but then we have that <place> element which is a container and not a data element itself, so we cannot use an input tag for it.

Here's where the <fieldset> tag comes in handy! We'll use <fieldset> tags to represent all container elements in our form/XML representation and so getting to a result like this:

<form name="places">

    <fieldset name="place">

        <input type="text" name="name"/>
        <select name="type">
            <option value="dwelling">Dwelling</option>
            <option value="restoration">Restoration</option>
            <option value="sport">Sport</option>
            <option value="administrative">Administrative</option>
        </select>

        <input type="text" name="activity"/>
        <input type="text" name="activity"/>
        <input type="text" name="activity"/>

    </fieldset>

</form>

As you can see in this form, we're breaking the rule of unique names, but this is OK because they'll be converted into an array of element thus they'll be referenced only by their index inside the array.

At this point you can see how there's no name="array[]" like name inside the form and everything is pretty, simple and semantic.

Now we want this form to be converted into a JSON object which will look like this:

{'places':{

    'place':[

        {

            'name': 'Home',
            'type': 'dwelling',

            'activity':[

                 'sleep',
                 'eat',
                 'watch TV'

            ]

        },

        {...},

        {...}

    ]

}}

To do this I have developed this jQuery plugin here which someone helped optimizing in this Code Review thread and looks like this:

$.fn.toJSO = function () {
    var obj = {},
        $kids = $(this).children('[name]');
    if (!$kids.length) {
        return $(this).val();
    }
    $kids.each(function () {
        var $el = $(this),
            name = $el.attr('name');
        if ($el.siblings("[name=" + name + "]").length) {
            if (!/radio|checkbox/i.test($el.attr('type')) || $el.prop('checked')) {
                obj[name] = obj[name] || [];
                obj[name].push($el.toJSO());
            }
        } else {
            obj[name] = $el.toJSO();
        }
    });
    return obj;
};

I also made this one blog post to explain this more.

This converts everything in a form to JSON (even radio and check boxes) and all you'll have left to do is call

$.post('script.php',('form').toJSO(), ...);

I know there's plenty of ways to convert forms into JSON objects and sure .serialize() and .serializeArray() work great in most cases and are mostly intended to be used, but I think this whole idea of writing a form as an XML structure with meaningful names and converting it into a well-formed JSON object is worth the try, also the fact you can add same-name input tags without worrying is very useful if you need to retrive dynamically generated forms data.

I hope this helps someone!

Community
  • 1
  • 1
Onheiron
  • 1,993
  • 1
  • 23
  • 36
2

For a quick, modern solution, use the JSONify jQuery plugin. The example below is taken verbatim from the GitHub README. All credit to Kushal Pandya, author of the plugin.

Given:

<form id="myform">
    <label>Name:</label>
    <input type="text" name="name"/>
    <label>Email</label>
    <input type="text" name="email"/>
    <label>Password</label>
    <input type="password" name="password"/>
</form>

Running:

$('#myform').jsonify();

Produces:

{"name":"Joe User","email":"joe@example.com","password":"mypass"}

If you want to do a jQuery POST with this JSON object:

$('#mybutton').click(function() {
    $.post('/api/user', JSON.stringify($('#myform').jsonify()));
}
Jim Stewart
  • 15,555
  • 4
  • 60
  • 83
2

I coded a form to a multidimensional JavaScript object myself to use it in production. The result is https://github.com/serbanghita/formToObject.js.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Șerban Ghiță
  • 1,751
  • 18
  • 21
2

I like samuels version, but I believe it has a small error. Normally JSON is sent as

{"coreSKU":"PCGUYJS","name_de":"whatever",...

NOT as

[{"coreSKU":"PCGUYJS"},{"name_de":"whatever"},...

so the function IMO should read:

App.toJson = function( selector ) {
    var o = {};
    $.map( $( selector ), function( n,i )
    {
        o[n.name] = $(n).val();
    });     
    return o;
}

and to wrap it in data array (as commonly expected, too), and finally send it as astring App.stringify( {data:App.toJson( '#cropform :input' )} )

For the stringify look at Question 3593046 for the lean version, at json2.js for the every-eventuality-covered version. That should cover it all :)

Community
  • 1
  • 1
Frank Nocke
  • 7,493
  • 3
  • 58
  • 89
2

Here's a one-liner using reduce. Reduce is a functional function that takes the return value of the passed function and passes it back to the passed function in the next iteration, along with the nth value from the list.

$('#formid').serializeArray().reduce((o,p) => ({...o, [p.name]: p.value}))

We have to use a few of tricks to get this to work:

  • ...o (spread syntax) inserts all the key: value pairs from o
  • Wrap the object we are returning in () to distinguish it from the {} that denote a function
  • Wrap the key (p.name) in []
Zaz
  • 39,637
  • 10
  • 70
  • 92
  • 3
    I get wrong result if I don't add a init-object to that function: $('form').serializeArray().reduce((o, p) => ({...o, [p.name]: p.value}), {}) – Paflow Feb 25 '20 at 10:57
2

Taking advantage of ES6 goodness in a one liner:

$("form").serializeArray().reduce((o, {name: n, value: v}) => Object.assign(o, { [n]: v }), {});
Arik
  • 3,779
  • 1
  • 18
  • 20
2

I found a problem with the selected solution.

When using forms that have array based names the jQuery serializeArray() function actually dies.

I have a PHP framework that uses array-based field names to allow for the same form to be put onto the same page multiple times in multiple views. This can be handy to put both add, edit and delete on the same page without conflicting form models.

Since I wanted to seralize the forms without having to take this absolute base functionality out I decided to write my own seralizeArray():

        var $vals = {};

        $("#video_edit_form input").each(function(i){
            var name = $(this).attr("name").replace(/editSingleForm\[/i, '');

            name = name.replace(/\]/i, '');

            switch($(this).attr("type")){
                case "text":
                    $vals[name] = $(this).val();
                    break;
                case "checkbox":
                    if($(this).attr("checked")){
                        $vals[name] = $(this).val();
                    }
                    break;
                case "radio":
                    if($(this).attr("checked")){
                        $vals[name] = $(this).val();
                    }
                    break;
                default:
                    break;
            }
        });

Please note: This also works outside of form submit() so if an error occurs in the rest of your code the form won't submit if you place on a link button saying "save changes".

Also note that this function should never be used to validate the form only to gather the data to send to the server-side for validation. Using such weak and mass-assigned code WILL cause XSS, etc.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Sammaye
  • 40,888
  • 7
  • 90
  • 139
2

Turn anything into an object (not unit tested)

<script type="text/javascript">
string = {};

string.repeat = function(string, count)
{
    return new Array(count+1).join(string);
}

string.count = function(string)
{
    var count = 0;

    for (var i=1; i<arguments.length; i++)
    {
        var results = string.match(new RegExp(arguments[i], 'g'));
        count += results ? results.length : 0;
    }

    return count;
}

array = {};

array.merge = function(arr1, arr2)
{
    for (var i in arr2)
    {
        if (arr1[i] && typeof arr1[i] == 'object' && typeof arr2[i] == 'object')
            arr1[i] = array.merge(arr1[i], arr2[i]);
        else
            arr1[i] = arr2[i]
    }

    return arr1;
}

array.print = function(obj)
{
    var arr = [];
    $.each(obj, function(key, val) {
        var next = key + ": ";
        next += $.isPlainObject(val) ? array.print(val) : val;
        arr.push( next );
      });

    return "{ " +  arr.join(", ") + " }";
}

node = {};

node.objectify = function(node, params)
{
    if (!params)
        params = {};

    if (!params.selector)
        params.selector = "*";

    if (!params.key)
        params.key = "name";

    if (!params.value)
        params.value = "value";

    var o = {};
    var indexes = {};

    $(node).find(params.selector+"["+params.key+"]").each(function()
    {
        var name = $(this).attr(params.key),
            value = $(this).attr(params.value);

        var obj = $.parseJSON("{"+name.replace(/([^\[]*)/, function()
        {
            return '"'+arguments[1]+'"';
        }).replace(/\[(.*?)\]/gi, function()
        {
            if (arguments[1].length == 0)
            {
                var index = arguments[3].substring(0, arguments[2]);
                indexes[index] = indexes[index] !== undefined ? indexes[index]+1 : 0;

                return ':{"'+indexes[index]+'"';
            }
            else
                return ':{"'+escape(arguments[1])+'"';
        })+':"'+value.replace(/[\\"]/gi, function()
        {
            return "\\"+arguments[0]; 
        })+'"'+string.repeat('}', string.count(name, ']'))+"}");

        o = array.merge(o, obj);
    });

    return o;
}
</script>

The output of test:

$(document).ready(function()
{
    console.log(array.print(node.objectify($("form"), {})));
    console.log(array.print(node.objectify($("form"), {selector: "select"})));
});

on

<form>
    <input name='input[a]' type='text' value='text'/>
    <select name='input[b]'>
        <option>select</option>
    </select>

    <input name='otherinput[c][a]' value='a'/>
    <input name='otherinput[c][]' value='b'/>
    <input name='otherinput[d][b]' value='c'/>
    <input name='otherinput[c][]' value='d'/>

    <input type='hidden' name='anotherinput' value='hidden'/>
    <input type='hidden' name='anotherinput' value='1'/>

    <input type='submit' value='submit'/>
</form>

will yield:

{ input: { a: text, b: select }, otherinput: { c: { a: a, 0: b, 1: d }, d: { b: c } }, anotherinput: 1 }
{ input: { b: select } }
eithed
  • 3,110
  • 3
  • 34
  • 46
1

using lodash#set

let serialized = [
  { key: 'data[model][id]', value: 1 },
  { key: 'data[model][name]', value: 'product' },
  { key: 'sid', value: 'dh0un1hr4d' }
];

serialized.reduce(function(res, item) {
  _.set(res, item.key, item.value);
  return res;
}, {});

// returns
{
  "data": {
    "model": {
      "id": 1,
      "name": "product"
    }
  },
  "sid": "dh0un1hr4d"
}
Ivan Nosov
  • 11,641
  • 2
  • 14
  • 12
  • I 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 } }`. – supertrue Apr 10 '17 at 16:17
1

So I used the accepted answer and found a major flaw.
It doesn't support input arrays like:

<input type="checkbox" name="array[]" value="1"/>
<input type="checkbox" name="array[]" value="2"/>
<input type="checkbox" name="array[]" value="3"/>

This minor change should fix that:

function objectifyForm(inp){
    var rObject = {};
    for (var i = 0; i < inp.length; i++){
        if(inp[i]['name'].substr(inp[i]['name'].length - 2) == "[]"){
            var tmp = inp[i]['name'].substr(0, inp[i]['name'].length-2);
            if(Array.isArray(rObject[tmp])){
                rObject[tmp].push(inp[i]['value']);
            } else{
                rObject[tmp] = [];
                rObject[tmp].push(inp[i]['value']);
            }
        } else{
            rObject[inp[i]['name']] = inp[i]['value'];
        }
    }
    return rObject;
}

Remember to pass it the output from $(this).serializeArray(); otherwise it wont work.

Folkmann
  • 4,918
  • 3
  • 11
  • 12
1

A more modern way is to use reduce with serializeArray() in this way:

$('#formid').serializeArray()
    .reduce((a, x) => ({ ...a, [x.name]: x.value }), {});

It will help for many of the 'normal' cases.

For the very common instance where there are multiple tags with duplicate name attributes, this is not enough.

Since inputs with duplicate name attributes are normally inside some 'wrapper' (div, ul, tr, ...), like in this exemple:

  <div class="wrapperClass">
    <input type="text" name="one">
    <input type="text" name="two">
  </div>
  <div class="wrapperClass">
    <input type="text" name="one">
    <input type="text" name="two">
  </div>

one can use reduce with the map operator to iterate on them:

$(".wrapperClass").map(function () {
  return $(this).find('*').serializeArray()
    .reduce((a, x) => ({ ...a, [x.name]: x.value }), {});
}).get();

The result will be an array of objects in the format:

  [
    {
      one: valueOfOne,
      two: valueOfTwo
    }, {
      one: valueOfOne,
      two: valueOfTwo
    }
  ]

The .get() operator is used in conjunction with map to get the basic array instead of the jQuery object which gives a cleaner result. jQuery docs

user3658510
  • 1,370
  • 1
  • 11
  • 11
0

Tobias's solution above is the correct one, however, as commenter @macek pointed out, it does not handle inputs of type foo[bar] and split them into sub-objects.

This is a PHP-only feature, but I still find it very useful to be able to generate the same structure in JavaScript.

I simply modified Tobias's code above, so all credit goes to him. This can probably be made cleaner, but I just whipped it up in five minutes and thought it might be useful.

It does not handle multidimensional arrays or numerically indexed arrays at this time. That is, it will only work with names foo[bar] and not foo[].

jQuery.fn.serializeObjectPHP = function()
{
    var o = {};
    var re = /^(.+)\[(.*)\]$/;
    var a = this.serializeArray();
    var n;
    jQuery.each(a, function() {
        var name = this.name;
        if ((n = re.exec(this.name)) && n[2]) {
            if (o[n[1]] === undefined) {
                o[n[1]] = {};
                o[n[1]][n[2]] = this.value || '';
            } else if (o[n[1]][n[2]] === undefined) {
                o[n[1]][n[2]] = this.value || '';
            } else {
                if(!o[n[1]][n[2]].push) {
                    o[n[1]][n[2]] = [ o[n[1]][n[2]] ];
                }
                o[n[1]][n[2]].push(this.value || '');
            }
        } else {
            if (n && !n[2]) {
                name = n[1];
            }
            if (o[name] !== undefined) {
                if (!o[name].push) {
                    o[name] = [o[name]];
                }
                o[name].push(this.value || '');
            } else {
                o[name] = this.value || '';
            }
        }
    });
    return o;
};
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Kevin Jhangiani
  • 1,557
  • 2
  • 13
  • 23
  • it seems as though you didn't read my entire comment. I devised a solution that handles `foo[bar]`-type inputs as well as `foo[bar][bof][a][b][c][etc]`; see my answer in this thread. Also note that `foo[bar]` "parsing" is not unique to PHP. Rails heavily relies on this convention for passing form attributes to objects. – maček May 22 '12 at 03:32
0

I wouldn't use this on a live site due to XSS attacks and probably plenty of other issues, but here's a quick example of what you could do:

$("#myform").submit(function(){
    var arr = $(this).serializeArray();
    var json = "";
    jQuery.each(arr, function(){
        jQuery.each(this, function(i, val){
            if (i=="name") {
                json += '"' + val + '":';
            } else if (i=="value") {
                json += '"' + val.replace(/"/g, '\\"') + '",';
            }
        });
    });
    json = "{" + json.substring(0, json.length - 1) + "}";
    // do something with json
    return false;
});
Jason Berry
  • 2,439
  • 1
  • 16
  • 21
  • Couldn't you get around XSS attacks by converting them to JS object first, instead of directly to string? – davidtgq May 27 '16 at 01:16
0

This is an improvement for Tobias Cohen's function, which works well with multidimensional arrays:

http://jsfiddle.net/BNnwF/2/

However, this is not a jQuery plugin, but it will only take a few seconds to make it into one if you wish to use it that way: simply replace the function declaration wrapper:

function serializeFormObject(form)
{
    ...
}

with:

$.fn.serializeFormObject = function()
{
    var form = this;
    ...
};

I guess it is similar to macek's solution in that it does the same thing, but i think this is a bit cleaner and simpler. I also included macek's test case inputs into the fiddle and added some additional ones. So far this works well for me.

function serializeFormObject(form)
{
    function trim(str)
    {
        return str.replace(/^\s+|\s+$/g,"");
    }

    var o = {};
    var a = $(form).serializeArray();
    $.each(a, function() {
        var nameParts = this.name.split('[');
        if (nameParts.length == 1) {
            // New value is not an array - so we simply add the new
            // value to the result object
            if (o[this.name] !== undefined) {
                if (!o[this.name].push) {
                    o[this.name] = [o[this.name]];
                }
                o[this.name].push(this.value || '');
            } else {
                o[this.name] = this.value || '';
            }
        }
        else {
            // New value is an array - we need to merge it into the
            // existing result object
            $.each(nameParts, function (index) {
                nameParts[index] = this.replace(/\]$/, '');
            });

            // This $.each merges the new value in, part by part
            var arrItem = this;
            var temp = o;
            $.each(nameParts, function (index) {
                var next;
                var nextNamePart;
                if (index >= nameParts.length - 1)
                    next = arrItem.value || '';
                else {
                    nextNamePart = nameParts[index + 1];
                    if (trim(this) != '' && temp[this] !== undefined)
                        next = temp[this];
                    else {
                        if (trim(nextNamePart) == '')
                            next = [];
                        else
                            next = {};
                    }
                }

                if (trim(this) == '') {
                    temp.push(next);
                } else
                    temp[this] = next;

                temp = next;
            });
        }
    });
    return o;
}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Kipras
  • 2,427
  • 1
  • 14
  • 9
0

My code from my library phery got a serialization routine that can deal with really complex forms (like in the demo https://github.com/pocesar/phery/blob/master/demo.php#L1664 ), and it's not a one-size-fits-all. It actually checks what the type of each field is. For example, a radio box isn't the same as a range, that isn't the same as keygen, that isn't the same as select multiple. My function covers it all, and you can see it at https://github.com/pocesar/phery/blob/master/phery.js#L1851.

serializeForm:function (opt) {
    opt = $.extend({}, opt);

    if (typeof opt['disabled'] === 'undefined' || opt['disabled'] === null) {
        opt['disabled'] = false;
    }
    if (typeof opt['all'] === 'undefined' || opt['all'] === null) {
        opt['all'] = false;
    }
    if (typeof opt['empty'] === 'undefined' || opt['empty'] === null) {
        opt['empty'] = true;
    }

    var
        $form = $(this),
        result = {},
        formValues =
            $form
                .find('input,textarea,select,keygen')
                .filter(function () {
                    var ret = true;
                    if (!opt['disabled']) {
                        ret = !this.disabled;
                    }
                    return ret && $.trim(this.name);
                })
                .map(function () {
                    var
                        $this = $(this),
                        radios,
                        options,
                        value = null;

                    if ($this.is('[type="radio"]') || $this.is('[type="checkbox"]')) {
                        if ($this.is('[type="radio"]')) {
                            radios = $form.find('[type="radio"][name="' + this.name + '"]');
                            if (radios.filter('[checked]').size()) {
                                value = radios.filter('[checked]').val();
                            }
                        } else if ($this.prop('checked')) {
                            value = $this.is('[value]') ? $this.val() : 1;
                        }
                    } else if ($this.is('select')) {
                        options = $this.find('option').filter(':selected');
                        if ($this.prop('multiple')) {
                            value = options.map(function () {
                                return this.value || this.innerHTML;
                            }).get();
                        } else {
                            value = options.val();
                        }
                    } else {
                        value = $this.val();
                    }

                    return {
                        'name':this.name || null,
                        'value':value
                    };
                }).get();

    if (formValues) {
        var
            i,
            value,
            name,
            $matches,
            len,
            offset,
            j,
            fields;

        for (i = 0; i < formValues.length; i++) {
            name = formValues[i].name;
            value = formValues[i].value;

            if (!opt['all']) {
                if (value === null) {
                    continue;
                }
            } else {
                if (value === null) {
                    value = '';
                }
            }

            if (value === '' && !opt['empty']) {
                continue;
            }

            if (!name) {
                continue;
            }

            $matches = name.split(/\[/);

            len = $matches.length;

            for (j = 1; j < len; j++) {
                $matches[j] = $matches[j].replace(/\]/g, '');
            }

            fields = [];

            for (j = 0; j < len; j++) {
                if ($matches[j] || j < len - 1) {
                    fields.push($matches[j].replace("'", ''));
                }
            }

            if ($matches[len - 1] === '') {
                offset = assign_object(result, fields, [], true, false, false);

                if (value.constructor === Array) {
                    offset[0][offset[1]].concat(value);
                } else {
                    offset[0][offset[1]].push(value);
                }
            } else {
                assign_object(result, fields, value);
            }
        }
    }

    return result;
}

It's part of my library phery, but it can be ported to your own project. It creates arrays where there should be arrays, it gets the correct selected options from the select, normalize checkbox options, etc. If you want to convert it to JSON (a real JSON string), just do JSON.stringify($('form').serializeForm());

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
pocesar
  • 6,379
  • 6
  • 49
  • 83
0

This solution is better. Some of the more popular options on here don't correct handle checkboxes when the checkbox is not checked.

       getData: function(element){
      //@todo may need additional logic for radio buttons
      var select = $(element).find('select');
      var input = $(element).find('input');
      var inputs = $.merge(select,input);
      var data = {};
      //console.log(input,'input');
      $.each(inputs,function(){
        if($(this).attr('type') != undefined){
          switch($(this).attr('type')){
            case 'checkbox':
              data[$(this).attr('name')] = ( ($(this).attr('checked') == 'checked') ? $(this).val():0 );
              break;
            default:
              data[$(this).attr('name')] = $(this).val();
              break;
          }
        }
        else{
          data[$(this).attr('name')] = $(this).val();
        }
      })
      return data;
   }
cnizzardini
  • 1,095
  • 1
  • 12
  • 24
0

I wrote a jQuery module, jsForm, that can do this bidirectional even for quite complicated forms (allows collections and other more complex structures as well).

It uses the name of the fields (plus a few special classes for collections) and matches a JSON object. It allows automatic replication of DOM-elements for collections and data handling:

<html>
    <head>
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
        <script src="https://raw.github.com/corinis/jsForm/master/src/jquery.jsForm.js"></script>
        <script>
        $(function(){
            // Some JSON data
            var jsonData = {
                name: "TestName",   // Standard inputs
                description: "long Description\nMultiline", // Textarea
                links: [{href:'http://stackoverflow.com',description:'StackOverflow'}, {href:'http://www.github.com', description:'GitHub'}],   // Lists
                active: true,   // Checkbox
                state: "VISIBLE"    // Selects (enums)
            };

            // Initialize the form, prefix is optional and defaults to data
            $("#details").jsForm({
                data:jsonData
            });

            $("#show").click(function() {
                // Show the JSON data
                alert(JSON.stringify($("#details").jsForm("get"), null, " "));
            });
        });
        </script>
    </head>
    <body>
        <h1>Simpel Form Test</h1>
        <div id="details">
            Name: <input name="data.name"/><br/>
            <input type="checkbox" name="data.active"/> active<br/>
            <textarea name="data.description"></textarea><br/>
            <select name="data.state">
                <option value="VISIBLE">visible</option>
                <option value="IMPORTANT">important</option>
                <option value="HIDDEN">hidden</option>
            </select>
            <fieldset>
                <legend>Links</legend>
                <ul class="collection" data-field="data.links">
                    <li><span class="field">links.description</span> Link: <input name="links.href"/> <button class="delete">x</button></li>
                </ul>
            </fieldset>
            <button class="add" data-field="data.links">add a link</button><br/>
            Additional field: <input name="data.addedField"/>
        </div>
        <button id="show">Show Object</button>
    </body>
</html>
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Niko
  • 5,753
  • 2
  • 33
  • 48
0

If you are sending a form with JSON you must remove [] in sending the string. You can do that with the jQuery function serializeObject():

var frm = $(document.myform);
var data = JSON.stringify(frm.serializeObject());

$.fn.serializeObject = function() {
    var o = {};
    //var a = this.serializeArray();
    $(this).find('input[type="hidden"], input[type="text"], input[type="password"], input[type="checkbox"]:checked, input[type="radio"]:checked, select').each(function() {
        if ($(this).attr('type') == 'hidden') { //If checkbox is checked do not take the hidden field
            var $parent = $(this).parent();
            var $chb = $parent.find('input[type="checkbox"][name="' + this.name.replace(/\[/g, '\[').replace(/\]/g, '\]') + '"]');
            if ($chb != null) {
                if ($chb.prop('checked')) return;
            }
        }
        if (this.name === null || this.name === undefined || this.name === '')
            return;
        var elemValue = null;
        if ($(this).is('select'))
            elemValue = $(this).find('option:selected').val();
        else
            elemValue = this.value;
        if (o[this.name] !== undefined) {
            if (!o[this.name].push) {
                o[this.name] = [o[this.name]];
            }
            o[this.name].push(elemValue || '');
        }
        else {
            o[this.name] = elemValue || '';
        }
    });
    return o;
}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Harini Sekar
  • 630
  • 7
  • 14
0

I recently had the same problem so I developed a function that allows parsing a form's controls to obtain control id/value and convert that to JSON.

It is flexible enough to allow adding more controls. You just need to specify the control type and the attribute that you want to interpreted as value.

You can find the full script here.

The advantage is that it only takes the data you actually need, without dragging the whole object.

The dissadvantage is that if you have nested options, you need to prefix the IDs accordingly so you can use a duplicate option to its specific group.

I hope this helps!

Florin Mircea
  • 831
  • 12
  • 18
0

I had to shameless self-promote my form library.

transForm.js

It does things like: serialize, deserialize, clear & submit forms.

The reason why I made this is form2js/js2form is not maintained and is not as flexible & fast as I would like. We use it in production because this is form2js/js2form compatible.

A1rPun
  • 14,111
  • 6
  • 51
  • 79
0

If you want to convert a form to a javascript object, then the easiest solution (at this time) is to use jQuery's each and serializeArray function-methods.

$.fn.serializeObject = function() {

  var form = {};
  $.each($(this).serializeArray(), function (i, field) {
    form[field.name] = field.value || "";
  });

  return form;
};

Plugin hosted on GitHub:
https://github.com/tfmontague/form-object/blob/master/README.md

Can be installed with Bower:
bower install git://github.com/tfmontague/form-object.git

tim-montague
  • 12,048
  • 2
  • 50
  • 40
0

Here's a non-jQuery way:

    var getFormData = function(form) {
        //Ignore the submit button
        var elements = Array.prototype.filter.call(form.elements, function(element) {
            var type = element.getAttribute('type');
            return !type || type.toLowerCase() !== 'submit';
        });

You can use it like this:

function() {

    var getFormData = function(form) {
        //Ignore the submit button
        var elements = Array.prototype.filter.call(form.elements, function(element) {
            var type = element.getAttribute('type');
            return !type || type.toLowerCase() !== 'submit';
        });

        //Make an object out of the form data: {name: value}
        var data = elements.reduce(function(data, element) {
            data[element.name] = element.value;
            return data;
        }, {});

        return data;
    };

    var post = function(action, data, callback) {
        var request = new XMLHttpRequest();
        request.onload = callback;
        request.open('post', action);
        request.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
        request.send(JSON.stringify(data), true);
        request.send();
    };

    var submit = function(e) {
        e.preventDefault();
        var form = e.target;
        var action = form.action;
        var data = getFormData(form);
        //change the third argument in order to do something
        //more intersting with the response than just print it
        post(action, data, console.log.bind(console));
    }

    //change formName below
    document.formName.onsubmit = submit;

})();
Max Heiber
  • 10,336
  • 4
  • 47
  • 67
0

Javascript / jQuery one-liner-ish - which works on older versions too (pre ES6):

$('form').serializeArray().reduce((f,c) => {f[c['name']]=(f[c['name']])?[].concat(f[c['name']],c['value']):c['value']; return f}, {} );
ShQ
  • 666
  • 6
  • 9
0

This code working for me :

  var data = $('#myForm input, #myForm select, #myForm textarea').toArray().reduce(function (m, e) {
            m[e.name] = $(e).val();
            return m;
        }, {});
Abd Abughazaleh
  • 1,259
  • 9
  • 28
0

You might not need jQuery for this task. FormData is a perfect solution for this.

Here is the code that use FormData to collect input values, and use dot-prop to transform the values into nested objects.

CodeSandbox Demo

Anh Tran
  • 270
  • 3
  • 13
0

This code convert and save type of inputs and not convert all to string:

jQuery.fn.serializeForm = function () {
    var form = this.get(0);
    var i = [];
    var ret = {};
    for (i = form.elements.length - 1; i >= 0; i = i - 1) {
        if (form.elements[i].name === "") {
            continue;
        }
        var name = form.elements[i].name;
        switch (form.elements[i].nodeName) {
            case 'INPUT':
                switch (form.elements[i].type) {
                    case 'text':
                    case 'tel':
                    case 'email':
                    case 'hidden':
                    case 'password':
                        ret[name] = encodeURIComponent(form.elements[i].value);
                        break;
                    case 'checkbox':
                    case 'radio':
                        ret[name] = form.elements[i].checked;
                        break;
                    case 'number':
                        ret[name] = parseFloat(form.elements[i].value);
                        break;
                }
                break;
            case 'SELECT':
            case 'TEXTAREA':
                ret[name] = encodeURIComponent(form.elements[i].value);
                break;
        }
    }
    return ret;
};

For example this is output:

Day: 13
Key: ""
Month: 5
OnlyPayed: true
SearchMode: "0"
Year: 2021

instead of

Day: "13"
Key: ""
Month: "5"
OnlyPayed: "true"
SearchMode: "0"
Year: "2021"
MohsenB
  • 1,223
  • 14
  • 27
-1

This function returns all values converted to the right type;

bool/string/(integer/floats) possible

Tho you kinda need jQuery for this, but since serializeArray is jQuery too, so no big deal imho.

/**
 * serialized a form to a json object
 *
 * @usage: $("#myform").jsonSerialize();
 *
 */

(function($) {
    "use strict";
    $.fn.jsonSerialize = function() {
        var json = {};
        var array = $(this).serializeArray();
        $.each(array, function(key, obj) {
            var value = (obj.value == "") ? false : obj.value;
            if(value) {
                // check if we have a number
                var isNum = /^\d+$/.test(value);
                if(isNum) value = parseFloat(value);
                // check if we have a boolean
                var isBool = /^(false|true)+$/.test(value);
                if(isBool) value = (value!=="false");
            }
            json[obj.name] = value;
        });
        return json;
    }
})(jQuery);
ceed
  • 639
  • 1
  • 6
  • 14
-1

Create a map and cycle all fields, saving their values.

var params = {};
$("#form").find("*[name]").each(function(){
    params[this.getAttribute("name")] = this.value;
});
GMchris
  • 4,499
  • 4
  • 20
  • 37
Justin Levene
  • 1,379
  • 14
  • 14
-1

The serialize function take JSON object as a parameter and return serialize String.

function serialize(object) {
            var _SPECIAL_CHARS = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, _CHARS = {
                '\b' : '\\b',
                '\t' : '\\t',
                '\n' : '\\n',
                '\f' : '\\f',
                '\r' : '\\r',
                '"' : '\\"',
                '\\' : '\\\\'
            }, EMPTY = '', OPEN_O = '{', CLOSE_O = '}', OPEN_A = '[', CLOSE_A = ']', COMMA = ',', COMMA_CR = ",\n", CR = "\n", COLON = ':', space = "", COLON_SP = ': ', stack = [], QUOTE = '"';
            function _char(c) {
                if (!_CHARS[c]) {
                    _CHARS[c] = '\\u' + ('0000' + (+(c.charCodeAt(0))).toString(16))
                        .slice(-4);
                }
                return _CHARS[c];
            }
            function _string(s) {
                return QUOTE + s.replace(_SPECIAL_CHARS, _char) + QUOTE;
                // return str.replace('\"','').replace('\"','');
            }

            function serialize(h, key) {
                var value = h[key], a = [], colon = ":", arr, i, keys, t, k, v;
                arr = value instanceof Array;
                stack.push(value);
                keys = value;
                i = 0;
                t = typeof value;
                switch (t) {
                    case "object" :
                        if(value==null){
                            return null;
                        }
                        break;
                    case "string" :
                        return _string(value);
                    case "number" :
                        return isFinite(value) ? value + EMPTY : NULL;
                    case "boolean" :
                        return value + EMPTY;
                    case "null" :
                        return null;
                    default :
                        return undefined;
                }
                arr = value.length === undefined ? false : true;

                if (arr) { // Array
                    for (i = value.length - 1; i >= 0; --i) {
                        a[i] = serialize(value, i) || NULL;
                    }
                }
                else { // Object
                    i = 0;
                    for (k in keys) {
                        if (keys.hasOwnProperty(k)) {
                            v = serialize(value, k);
                            if (v) {
                                a[i++] = _string(k) + colon + v;
                            }
                        }
                    }
                }

                stack.pop();
                if (space && a.length) {

                    return arr
                        ? "[" + _indent(a.join(COMMA_CR), space) + "\n]"
                        : "{\n" + _indent(a.join(COMMA_CR), space) + "\n}";
                }
                else {
                    return arr ? "[" + a.join(COMMA) + "]" : "{" + a.join(COMMA)
                        + "}";
                }
            }
            return serialize({
                "" : object
            }, "");
        }
Anoop
  • 22,031
  • 9
  • 59
  • 70
-7

Use this:

var sf = $('#mainForm').serialize(); // URL encoded string
sf = sf.replace(/"/g, '\"');         // Be sure all "s are escaped
sf = '{"' + sf.replace(/&/g, '","'); // Start "object", replace tupel delimiter &
sf = sf.replace(/=/g, '":"') + '"}'; // Replace equal sign, add closing "object"

// Test the "object"
var formdata = eval("(" + sf + ")"); 
console.log(formdata);

It works like a charm, even on very complex forms.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
xlthor
  • 17
  • 1