48

Is there any better solution to convert a form data that is already serialized by jQuery function serialize(), when the form contains multiple input Array fields. I want to be able to convert the form data in to a JSON object to recreate some other informative tables. So tell me a better way to get the serialize string converted as a JSON object.

<form id='sampleform'>
    <input name='MyName' type='text' /> // Raf

    <!--array input fields below-->
    <input name='friendname[]' type='text' /> // Bily
    <input name='fiendemail[]' type='text' /> // bily@someemail.com

    <!--duplicated fields below to add more friends -->
    <input name='friendname[]' type='text' /> // Andy
    <input name='fiendemail[]' type='text' /> // Andy@somwhere.com

    <input name='friendname[]' type='text' /> // Adam
    <input name='fiendemail[]' type='text' /> // Adam@herenthere.com
</form>

The jquery method applied to get the data

var MyForm = $("#sampleform").serialize();
/** result : MyName=Raf&friendname[]=Billy&fiendemail[]=bily@someemail.com&friendname[]=Andy&fiendemail[]=Andy@somwhere.com&friendname[]=Adam&fiendemail[]=Adam@herenthere.com
*/

how do I make this data in to a JSON object? which should have the following example JSON data from the above form.

{
    "MyName":"raf",
    "friendname":[
        {"0":"Bily"},
        {"1":"Andy"},
        {"2":"Adam"}
    ],
    "friendemail":[
        {"0":"bily@someemail.com"},
        {"1":"Andy@somwhere.com"},
        {"2":"Adam@herenthere.com"}
    ]
}
allicarn
  • 2,859
  • 2
  • 28
  • 47
Raftalks
  • 2,017
  • 1
  • 21
  • 25
  • 2
    Technically, that's not how the JSON object would be formatted based on your query string. Specifically, the array elements would not be objects with indexes, but just values. With that said, if you require the format you posted, you will probably need to write a custom function. – Jason McCreary Jul 18 '10 at 23:28
  • 1
    possible duplicate of [Serialize form to JSON with jQuery](http://stackoverflow.com/questions/1184624/serialize-form-to-json-with-jquery) – SLaks Jul 18 '10 at 23:38
  • Thanks Slaks and Jason, yes I do agree that I need a function to do it and Slaks have pointed it out for me. – Raftalks Jul 19 '10 at 00:23
  • You can use [this plugin](http://css-tricks.com/snippets/jquery/serialize-form-to-json/). – SLaks Jul 18 '10 at 23:36
  • 1
    2018 people, several years after this question being answered, I tried multiple solutions from here and RECOMEND [tothemario](https://stackoverflow.com/a/20986291/7083569) solution: https://github.com/marioizquierdo/jquery.serializeJSON It really works even when you use 'object[attribute]' form to name your inputs. – Dimas Crocco Apr 06 '18 at 17:17

13 Answers13

62
var formdata = $("#myform").serializeArray();
var data = {};
$(formdata ).each(function(index, obj){
    data[obj.name] = obj.value;
});

Simple and fast ;)

Danilo Colasso
  • 2,360
  • 17
  • 11
  • 10
    This doesn't generate a hierarchized JS object – Epoc Jan 22 '16 at 09:16
  • 2
    @Epoc What concept of hierarchy are you referring to? Form data is flat. – John Nov 07 '16 at 20:06
  • 1
    var formdata = $("#myform").serializeArray(); formdata = JSON.parse(formdata); //add this line var data = {}; $(formdata ).each(function(index, obj){ data[obj.name] = obj.value; }); – Mitin Dixit Apr 30 '17 at 19:46
  • 7
    **warning**: if you have multiple values with the same key (allowed in a Form) this will not preserve them and overwrite same-named values – Black Sep 06 '18 at 02:48
12

I have recently had this exact problem. 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.

Samuel Meacham
  • 10,215
  • 7
  • 44
  • 50
  • I just noticed you're using ‘friendname[]‘ as the name of your input elements, to capture an array of values as opposed to a single value. I don't think ‘$.map()‘ would work well for that. – Samuel Meacham Jul 19 '10 at 02:37
  • 2
    I think your map function is not quite right...you are returning a separate object for each attribute...dont' you want to put all attributes on a single object?...so declare the object outside the function, not inside (and don't return anything--use map for side-effects only) – Nick Perkins Apr 07 '11 at 19:30
  • +1; this solution is great. I just parameterized the part where you have `#container`, and instead of calling `console.log()` put the top part in a function. – mpontillo Jul 03 '13 at 02:44
  • Had to change `$(n).val()` to be `$(n).value` – dangerous.beans Mar 25 '15 at 21:50
10

Use the jQuery.serializeJSON plugin. It converts forms using the same format as what you would find in a Rails params object, which is very standard and well tested.

tothemario
  • 5,851
  • 3
  • 44
  • 39
6

I'm using this very little jQuery plugin, that I've extended from DocumentCloud:

https://github.com/documentcloud/documentcloud/blob/master/public/javascripts/lib/jquery_extensions.js

It is basically two lines of code, but it requires _.js (Underscore.js), since it is based on a reduce function.

$.fn.extend({
  serializeJSON: function(exclude) {
    exclude || (exclude = []);
    return _.reduce(this.serializeArray(), function(hash, pair) {
      pair.value && !(pair.name in exclude) && (hash[pair.name] = pair.value);
      return hash;
    }, {});
  }
});

Extensions:

  • It doesn't serialize an input value if it's null
  • It can exclude some inputs by passing an array of input names to the exclude argument i.e. ["password_confirm"]
Matt Fletcher
  • 8,182
  • 8
  • 41
  • 60
S.C.
  • 2,844
  • 3
  • 26
  • 27
6

I think there're a lot of good answer here, and I made my own function based on these answers.

function formToJSON(f) {
    var fd = $(f).serializeArray();
    var d = {};
    $(fd).each(function() {
        if (d[this.name] !== undefined){
            if (!Array.isArray(d[this.name])) {
                d[this.name] = [d[this.name]];
            }
            d[this.name].push(this.value);
        }else{
            d[this.name] = this.value;
        }
    });
    return d;
}

//The way to use it :
$('#myForm').submit(function(){
    var datas = formToJSON(this);
    return false;
});

Well let me explain basically why I prefer this solution... If you have multiples input with the same name, all values will be stored in an Array but if not, the value will be stored directly as the value of the index in the JSON ... This is where it's different from Danilo Colasso's answer where the JSON returned is only based of array values...

So if you have a Form with a textarea named content and multiples authors, this function will return to you :

{
    content : 'This is The Content',
    authors : 
        [
            0: 'me',
            1: 'you',
            2: 'him',
        ]
}
Simon Trichereau
  • 721
  • 11
  • 19
4

An equivalent solution to Danilo Colasso's, with the sames pros and cons of .serializeArray() (basically it uses .reduce instead of $.each).

With little effort it allows implementing the extra features in S.C.'s answers without requiring extensions.

$(selector).serializeArray()
    .reduce(function(accum, item) {
        // This 'if' allows ignoring some values
        if (-1 === [ 'ignoreThis', 'andThat' ].indexOf(item.name)) {
            // This allows ignoring NULL values
            if (item.value !== null) {
                accum[item.name] = item.value;
            }
        }
        return accum;
    },
    {
        // By supplying some initial values, we can add defaults
        // for, say, disabled form controls.
        preFilledName:  preFilledValue, // optional
        defaultName  :  defaultValue    // optional
    }
);
LSerni
  • 55,617
  • 10
  • 65
  • 107
4

if you can use ES6, you could do

const obj = arr.reduce((acc, {name, value}) => ({...acc, [name]: value}), {})

for a serialized array works very well.

3
var formdata = $("#myform").serializeArray();

var data = {};

$(formdata ).each(function(index, obj){

         if(data[obj.name] === undefined)
              data[obj.name] = [];

          data[obj.name].push(obj.value);

});
Petter Friberg
  • 21,252
  • 9
  • 60
  • 109
  • 1
    While this code snippet may solve the question, [including an explanation](//meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. Please also try not to crowd your code with explanatory comments, this reduces the readability of both the code and the explanations! – kayess Apr 11 '17 at 13:13
2

Using underscore & jQuery

var formdata = $("#myform").serializeArray();
var data = {};
_.each(formdata, function(element){
// Return all of the values of the object's properties.
  var value = _.values(element);
// name : value 
  data[value[0]] = value[1];
});
console.log(data); //Example => {name:"alex",lastname:"amador"}
alejandro
  • 2,799
  • 1
  • 17
  • 25
2

Using the power of reducing function!

$(form).serializeArray().reduce(function (output, value) {
        output[value.name] = value.value

        return output
}, {})
Aqib
  • 304
  • 3
  • 5
1

With all Given Answer there some problem which is...

If input name as array like name[key], but it will generate like this

 name:{
   key : value
 }

For Example : If i have form like this.

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

Then It will Generate Object like this with all given Answer.

Object {
    name : 'value',
    name1[key1] : 'value1',
    name2[key2] : 'value2',
    name3[key3] : 'value3', 
}

But it have to Generate like below,anyone want to get like this as below.

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

Then Try this below js code.

(function($) {
  $.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());
  });
})(jQuery);
console.log($('form').getForm2obj());
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<form>
  <input name="name" value="value">
  <input name="name1[key1]" value="value1">
  <input name="name2[key2]" value="value2">
  <input name="name3[key3]" value="value3">
  <input type="checkbox" name="name4[]" value="1" checked="checked">
  <input type="checkbox" name="name4[]" value="2">
  <input type="checkbox" name="name4[]" value="3">
</form>
Bhavik Hirani
  • 1,996
  • 4
  • 28
  • 46
0

if you are using ajax requests then no need to make it json-object only $('#sampleform').serialize() works excellently or if you have another purpose here is my solution:

var formserializeArray = $("#sampleform").serializeArray();   
var jsonObj = {};
jQuery.map(formserializeArray , function (n, i) {
    jsonObj[n.name] = n.value;
});
Haritsinh Gohil
  • 5,818
  • 48
  • 50
0

Use JSON.stringify() and serializeArray():

console.log(JSON.stringify($('#sampleform').serializeArray()));