24

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

like this one:

{ fields: { name: 'foo', email: '[email protected]', comment: 'wqeqwtwqtqwtqwet' } } 

assuming the form looks like this:

<form> <input type="text" name="name" value="foo" /> <input type="text" name="email" value="[email protected]" /> <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.

2
  • What's the mission? What are you intending to do with this object? Commented Apr 9, 2011 at 5: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... Commented Apr 9, 2011 at 5:46

11 Answers 11

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`... } }); 
Sign up to request clarification or add additional context in comments.

5 Comments

thank you :P yes I need a fields property because I'm passing other properites too and don't want to confuse them
You might want to add .not("button") before .each since buttons are included as input fields
@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...
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 <select> is a special case as well.
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.
11
var inputs = $("form :input"); var obj = $.map(inputs, function(x, y) { return { Key: x.name, Value: $(x).val() }; }); console.log(obj); 

6 Comments

need to add the other form element types, but this is great
there are also other elements to consider than input such as select, textarea
:input works for all fields including textarea and select. I'm using :input not input. see example jsfiddle.net/ASe4S
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).
Check jsfiddle.net/ASe4S/1. Note serializearray does not work with disabled fields. map is a more flexible solution
|
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.

Comments

6

Here is a simple solution:

See Demo

$(".form-sample").serializeArray().map(function(x){data[x.name] = x.value;}); 

Comments

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.

2 Comments

serialize does not give JSON output as OP requested
@Hussein Thanks, then maybe serializeArray() will work, I've updated my answer.
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

Comments

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

1 Comment

Thanks! Works like a charm when a form has an array. Perfect solution.
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.

Comments

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

Comments

0

Simple form code

<form id="myForm" name="myForm"> <input type="text" name="email" value="[email protected]"/> <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; } } 

Comments

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 obj = Object.fromEntries(new FormData(formElement).entries()) console.log(obj) 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 }, {}) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.