I'm simply looking for a way to get all the values from a <form>.
I searched the Web for a while, stumbling across FormData, which seems quite what I'm looking for.
However its API is not available on any browser, so I need an alternative.
What I need in my specific case is an object of key/value pairs. For example:
<form>   <input type="text" name="firstname" value="John" />   <input type="text" name="surname" value="doe" />   <input type="email" name="email" value="" />   <input type="radio" name="gender" value="male" />   <input type="radio" name="gender" value="female" /> </form>   The object should be:
{   firstname: "John",   surname: "doe",   email: "",   gender: "" }   Edit: The above is just an example, it should work not only with <input> but also with the other tags (e.g. <select>, <textarea> and so on... even <input type="file"> should be supported). 
The form-data can be sent as URL variables (with method="get" ) or as HTTP post transaction (with method="post" ). Notes on GET: Appends form-data into the URL in name/value pairs. The length of a URL is limited (about 3000 characters)
How to retrieve form data sent via GET. When you submit a form through the GET method, PHP provides a superglobal variable, called $_GET. PHP uses this $_GET variable to create an associative array with keys to access all the sent information ( form data ). The keys is created using the element's name attribute values.
When I originally wrote this answer FormData was not widely supported (and this was called out explicitly in the question). Now that it's been 6 years, FormData has excellent cross-browser support.
Because of this, I highly recommend using FormData directly to access data or serialize data to the server.
Jake Archibald has an excellent post describing FormData (and URLSearchParams) in depth, which I won't attempt to reproduce here, however I will include a few snippets that are relevant:
You can populate
FormDatastate directly:const formData = new FormData(); formData.set('foo', 'bar'); formData.set('hello', 'world');
...you can read an HTML form directly as
FormData:const formElement = document.querySelector('form'); const formData = new FormData(formElement); console.log(formData.get('username'));
...you can use
FormDatadirectly as a fetch body:const formData = new FormData(); formData.set('foo', 'bar'); formData.set('hello', 'world'); fetch(url, { method: 'POST', body: formData, });
I recommend reading Jake's post in full and using the APIs that come with the browser over adding more code to build a less-resilient version of the same thing.
My original post preserved for posterity's sake:
Without a strong definition of what should happen with edge cases, and what level of browser support is required, it's difficult to give a single perfect answer to the question.
There are a lot of form behaviors that are easy to miss, which is why I recommend using a well-maintained function from a library, such as jQuery's serializeArray():
$('form').serializeArray();  I understand that there's a big push recently to move away from needlessly including jQuery, so for those who are interested in a vanilla JS solution serializeArray just won't do.
The next difficulty comes from determining what level of browser support is required. HTMLFormElement.elements significantly simplifies a serialization implementation, and selecting the form-associated elements without it is quite a pain.
Consider:
<form id="example">...</form> <input type="text" form="example" name="lorem" value="ipsum"/>  A conforming implementation needs to include the input element. I will assume that I can use it, and leave polyfilling it as an exercise to the reader.
After that it'd unclear how <input type="file"/> should be supported. I'm not keen on needlessly serializing file elements into a string, so I've made the assumption that the serialization will be of the input's name and value, even though the value is practically useless.
Lastly, an input structure of:
{     'input name': 'value',     'textarea name': 'value' }  Is excessively naive as it doesn't account for <select multiple> elements, or cases where two inputs have the same name. I've made the assumption that the input would be better as:
[     {         name: 'input name',         value: 'value'     },     {         name: 'textarea name',         value: 'value'     } ]  ...and again leave transforming this into a different structure as an exercise for the reader.
var serialize = (function (slice) {     return function (form) {         //no form, no serialization         if (form == null)             return null;          //get the form elements and convert to an array         return slice.call(form.elements)             .filter(function (element) {                 //remove disabled elements                 return !element.disabled;             }).filter(function (element) {                 //remove unchecked checkboxes and radio buttons                 return !/^input$/i.test(element.tagName) || !/^(?:checkbox|radio)$/i.test(element.type) || element.checked;             }).filter(function (element) {                 //remove <select multiple> elements with no values selected                 return !/^select$/i.test(element.tagName) || element.selectedOptions.length > 0;             }).map(function (element) {                 switch (element.tagName.toLowerCase()) {                     case 'checkbox':                     case 'radio':                         return {                             name: element.name,                             value: element.value === null ? 'on' : element.value                         };                     case 'select':                         if (element.multiple) {                             return {                                 name: element.name,                                 value: slice.call(element.selectedOptions)                                     .map(function (option) {                                         return option.value;                                     })                             };                         }                         return {                             name: element.name,                             value: element.value                         };                     default:                         return {                             name: element.name,                             value: element.value || ''                         };                 }             });     } }(Array.prototype.slice)); 
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With