24

How can I create a object with a form's fields and values?

like this one:

{
  fields:
   {
      name: 'foo',
      email: 'foo@moo.com',
      comment: 'wqeqwtwqtqwtqwet'     

   }
}

assuming the form looks like this:

<form>
  <input type="text" name="name" value="foo" />
  <input type="text" name="email" value="foo@moo.com" />
  <textarea name="comment">wqeqwtwqtqwtqwet</textarea>
</form>

I need to know how can I do this for any form with a single function, not just a particular form.

Alex
  • 66,732
  • 177
  • 439
  • 641
  • What's the mission? What are you intending to do with this object? – Canuteson Apr 09 '11 at 05:42
  • i'm trying to create a ajax script that validates forms. and some fields depend on other fields, so I just send the entire object on any input change... – Alex Apr 09 '11 at 05:46

11 Answers11

41

You can do this:

var fields = {};
$("#theForm").find(":input").each(function() {
    // The selector will match buttons; if you want to filter
    // them out, check `this.tagName` and `this.type`; see
    // below
    fields[this.name] = $(this).val();
});
var obj = {fields: fields}; // You said you wanted an object with a `fields` property, so...

Beware that forms can have fields with repeated names, and what you're trying to do doesn't support that. Also, the order of fields in HTML forms can be significant. (These are both reasons that serializeArray works the way it does.)

Note that normal HTML practice is to omit disabled fields. If you want to do that, check this.disabled before grabbing the value as well.


Note that the above (written two years ago) uses a jQuery pseudo-selector. I'm a bit surprised to find that I wrote that. As it says in the documentation for the :input pseudo-selector, using it means that jQuery can't hand off the selector to the browser's native querySelectorAll (which nearly all browsers now have).

Nowadays I'd probably write:

$("#theForm").find("input, textarea, select, button")...

...if I wanted buttons, or if not then

$("#theForm").find("input, textarea, select")...

...and then filter out input[type="button"] and input[type="submit"] inside the each. E.g. (no buttons at all):

$("#theForm").find("input, textarea, select").each(function() {
    var inputType = this.tagName.toUpperCase() === "INPUT" && this.type.toUpperCase();
    if (inputType !== "BUTTON" && inputType !== "SUBMIT") {
        // ...include it, either it's an `input` with a different `type`
        // or it's a `textarea` or a `select`...
    }
});
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • thank you :P yes I need a fields property because I'm passing other properites too and don't want to confuse them – Alex Apr 09 '11 at 05:59
  • You might want to add .not("button") before .each since buttons are included as input fields – Xerri May 29 '13 at 15:16
  • @thearchitect: Hence *"The selector will match buttons; if you want to filter them out, check `this.tagName` and `this.type`; see below"* :-) (Although I'm not seeing what "below" I was referring to!) I'm very surprised to see myself use a jQuery pseudo-selector in an answer, though. I guess it *was* two years ago... – T.J. Crowder May 29 '13 at 21:05
  • hehe......there are some other details anyone using this needs to keep in mind. Radio buttons and checkboxes need to be catered for. I had to switch to using the id of a field instead of the name because of radio buttons. I think – Xerri May 30 '13 at 08:44
  • Piggy-backing on @Xerri, another gotcha with radio buttons and checkboxes is that `.val()` won't give you the right thing - the value of these input types does not change whether it is checked or not. You want `.prop('checked')` or a similar method to get the checked property value. – internetross Feb 11 '15 at 18:24
11
var inputs = $("form :input");
var obj = $.map(inputs, function(x, y) {
    return {
        Key: x.name,
        Value: $(x).val()
    };
});
console.log(obj);
Hussein
  • 42,480
  • 25
  • 113
  • 143
  • need to add the other form element types, but this is great – Slappy Apr 09 '11 at 05:41
  • there are also other elements to consider than input such as select, textarea – gion_13 Apr 09 '11 at 05:41
  • `:input` works for all fields including textarea and select. I'm using `:input` not `input`. see example http://jsfiddle.net/ASe4S/ – Hussein Apr 09 '11 at 05:42
  • 4
    This doesn't produce the structure he asked for. This produces an array of objects, each with a single property based on the name of the field. Very difficult to use, he'd be better off using `serializeArray` as the property names (`name` and `value`) are defined (or, of course, something structured the way he *did* ask for, although that structure is limited as it doesn't support forms with repeated field names). – T.J. Crowder Apr 09 '11 at 05:48
  • Check http://jsfiddle.net/ASe4S/1/. Note serializearray does not work with disabled fields. map is a more flexible solution – Hussein Apr 09 '11 at 05:58
  • @Hussein: *"Note serializearray does not work with disabled fields"* `serializeArray` works exactly correctly with disabled fields, according to the HTML specification. They are omitted, by design. But my issue wasn't with your using `map`, it was with the original form of what you were creating. Your updated form is more useful, because at least the property names are defined, although it's still not what Alex asked for. – T.J. Crowder Apr 09 '11 at 06:20
6

As per a comment on the http://api.jquery.com/serializeArray/ page, you can do:

(function( $ ){
    $.fn.serializeJSON=function() {
        var json = {};
        jQuery.map($(this).serializeArray(), function(n, i){
            json[n['name']] = n['value'];
        });
        return json;
    };
})( jQuery );

Then do:

var obj = $('form').serializeJSON();

or if you need it with your fields property, you can modify the function or do this:

var obj = {fields: $('form').serializeJSON()};

Or you can just use serializeArray() if you don't mind that format of output.

Brett Zamir
  • 14,034
  • 6
  • 54
  • 77
4

Here is a simple solution:

See Demo

$(".form-sample").serializeArray().map(function(x){data[x.name] = x.value;});
DDan
  • 8,068
  • 5
  • 33
  • 52
3

jquery has a serialize() function on froms like $('#myform').serialize()

is this what you're looking for?

update: oops, maybe try serializeArray() instead, it should give you an array of name and value.

albb
  • 224
  • 1
  • 6
1

This way you catch all values from multiple selects or groups of checkboxes

function form2obj(form) {
    var arr = $(form).serializeArray(), obj = {};
    for(var i = 0; i < arr.length; i++) {
        if(obj[arr[i].name] === undefined) {
            obj[arr[i].name] = arr[i].value;
        } else {
            if(!(obj[arr[i].name] instanceof Array)) {
                obj[arr[i].name] = [obj[arr[i].name]];
            }
            obj[arr[i].name].push(arr[i].value);
        }
    }
    return obj;
};
user3504541
  • 81
  • 1
  • 2
1

A lot of complicated ways which do not work in some cases. In the meantime you can use the FormData

 var fields = {};
 var myform = document.getElementById('ThisIsTheIDOfMyForm');
 var myformdata = new FormData(myform);
 for (var [key, value] of myformdata.entries()) { 
    fields[key] = value;
 }
 console.log(fields);

is exactly what you want. It handles everything.

Jens H
  • 21
  • 2
1
function formsToObj(){
    var forms = [];
    $('form').each(function(i){
        forms[i] = {};
        $(this).children('input,textarea,select').each(function(){
            forms[i][$(this).attr('name')] = $(this).val();
        });
    });
    return forms;
}

it's a generalized function that creates an object for each form in your page

gion_13
  • 41,171
  • 10
  • 96
  • 108
0

So I always try to put a wrapper among form submits.

This is especially important for form submits that run over ajax.

The first thing to do is grab the form on submit.

$(".ajax-form").submit(function(){
    var formObject = objectifyForm($(this).serializeArray());
    // Do stuff with formObject 

    // always add return false to stop the form from actually doing a post anywhere
    return false;
});

This will wrap any form that has a class of "ajax-form" and send the serializeArray to a function that is called objectify form which will return an object of all of the values of that form.

function objectifyForm(formArray) {
    returnArray = {};
    for (var i = 0; i < formArray.length; i++) {
        returnArray[formArray[i]['name']] = formArray[i]['value'];
    }
    return returnArray;
}
Jordan
  • 96
  • 1
  • 4
0

Simple form code

<form id="myForm" name="myForm">
    <input type="text" name="email" value="fazelman@test.com"/>
    <input type="checkbox" name="gender">
    <input type="password" name="pass" value="123"/>
    <textarea name="message">Enter Your Message Her</textarea>
</form>

Javascript Code:

var data = {};
var element = document.getElementById("form").elements
for (var i = 0; i < element.length; i++) {
    switch (element[i].type) {
        case "text": data[element[i].name] = element[i].value; break;
        case "checkbox": data[element[i].name] = element[i].checked; break;
        case "password": data[element[i].name] = element[i].checked; break;
        case "textarea": data[element[i].name] = element[i].value; break;
    }
}
Afzaal Ahmad Zeeshan
  • 15,669
  • 12
  • 55
  • 103
Mohammad Fazeli
  • 648
  • 10
  • 13
0

If you want to spare any redundand element selectors, you can access the FormData from within the submit event handler function. The below code snippet will print out Object with searchTerm and includeBananas.

function submitForm(formElement) {
  const formData = new FormData(formElement)
  const allEntries = [...formData.entries()]
    .reduce((all, entry) => {
      all[entry[0]] = entry[1]
      return all
    }, {})
  console.log(allEntries)
  return false;
}
<form onsubmit="return submitForm(this)">
  <input name="searchTerm">
  <input name="includeBananas" type="checkbox">
  <button>Submit</button>
</form>

Edit: I found that this is missing one thing: FormData can hold multiple values for the same key. In that case, you would need something like

const allEntries = [...form_data.keys()].reduce((all, form_key) => {
    all[form_key] = form_data.getAll(form_key)
    return all
}, {})

phil294
  • 10,038
  • 8
  • 65
  • 98