14

I have form:

<form onchange="allvaluestostring()">
    <select name="status">
         <option value="*">All</option>
         <option value="1">Active</option>
         <option value="0">Inactive</option>
    </select>
    <select name="size">
          <option value="*">All</option>
          <option value="small">Small</option>
          <option value="big">Big</option>
    </select>
</form>

And the onchange action of any input in form I need to get a JavaScript string, for example "status=1&size=big" for using in httprequest.

Does there exist something in JavaScript that will take all form values when one of form inputs will be changed?

I used <select name="status" onchange="showExporteditems(this.name,this.value)">, but this will take only one input value for using only "status=1", but I need on each onchage all values from all inputs for string like "status=1&size=big&...etc....".

Without using jQuery.

Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Martin
  • 2,411
  • 6
  • 28
  • 51

8 Answers8

24

For input fields you could use ECMAScript 6 like the following:

Get your form in a constant:

const form = document.querySelector('form')

Grab all values:

Object.values(form).reduce((obj,field) => { obj[field.name] = field.value; return obj }, {})

The above snippet will produce an object with the input name as the key and its value.

Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Shairon Toledo
  • 1,779
  • 13
  • 18
  • 3
    This solution looks beautiful, but still has some issues: 1) There is still a big user base with browsers that don't support Object.values yet 2) the result includes values that are not form inputs. You could use `Object.values(form.elements)` to solve this. Would upvote if it had this fix and was based on Object.keys() instead :) – opyh Jan 26 '18 at 13:17
  • 2
    @opyh you may want to use babel when coding es6 you know – Teoman Tıngır Nov 15 '19 at 16:49
16

Here is a working fiddle in vanilla JavaScript, but you need to add a serialize utility function. This works exactly like $('form').serialize() in jQuery.

JavaScript:

var data;

function serialize(form) {
    if (!form || form.nodeName !== "FORM") {
        return;
    }
    var i, j, q = [];
    for (i = form.elements.length - 1; i >= 0; i = i - 1) {
        if (form.elements[i].name === "") {
            continue;
        }
        switch (form.elements[i].nodeName) {
        case 'INPUT':
            switch (form.elements[i].type) {
            case 'text':
            case 'hidden':
            case 'password':
            case 'button':
            case 'reset':
            case 'submit':
                q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
                break;
            case 'checkbox':
            case 'radio':
                if (form.elements[i].checked) {
                    q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
                }
                break;
            }
            break;
        case 'file':
            break;
        case 'TEXTAREA':
            q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
            break;
        case 'SELECT':
            switch (form.elements[i].type) {
            case 'select-one':
                q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
                break;
            case 'select-multiple':
                for (j = form.elements[i].options.length - 1; j >= 0; j = j - 1) {
                    if (form.elements[i].options[j].selected) {
                        q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].options[j].value));
                    }
                }
                break;
            }
            break;
        case 'BUTTON':
            switch (form.elements[i].type) {
            case 'reset':
            case 'submit':
            case 'button':
                q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
                break;
            }
            break;
        }
    }
    data = q.join("&");
}

And change your form onchange to

<form onchange="serialize(this)">

I tested it and am getting "size=small&status=0" in the console.

Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Seth
  • 9,662
  • 10
  • 42
  • 67
  • 1
    Put the function itself to the code, excelent solution! – Martin Apr 17 '14 at 18:01
  • This code is broken. having 3 – thenetimp Oct 28 '17 at 22:13
  • I can confirm that this is unfortunately broken - I would refactor it to not work with Switch Statements or else use better defaults, as it's far too easy to leave out input types like input[type="tel"]. – Bashu Naimi-Roy Jul 14 '20 at 03:03
10

I guess this would be a nice ECMAScript 6 vanilla JavaScript-based solution.

const form = document.getElementById("sampleForm");

form.addEventListener("submit", e => {
    e.preventDefault();
    let reqBody = {};
    Object.keys(form.elements).forEach(key => {
        let element = form.elements[key];
        if (element.type !== "submit") {
            reqBody[element.name] = element.value;
        }
    });
    submitForm(reqBody); // Call to function for form submission
});
Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Subhasis Das
  • 214
  • 4
  • 13
1

I don't know if there is an easier wait to do this but this solution, using just ECMAScript, is working for me:

function getPlainObjectFromFormElement(form) {
    const elements = form.elements;
    return Object.keys(elements)
        .reduce((obj, field) => {
            if (isNaN(field)) {
                obj[field] = elements[field].value;
            }
            return obj;
        }, {});
}

document.querySelector("form").onsubmit = function (e) {
    alert(JSON.stringify(getPlainObjectFromFormElement(e.target)));
}
dave008
  • 292
  • 2
  • 9
1

2021 version (TypeScript)

  const onSubmit = (e: any) => {
    e.preventDefault();
    const form = e.target as HTMLFormElement;
    const values = Object.fromEntries(
      Array.from(form.elements).map((x: Element) => {
        const input = x as HTMLInputElement;
        console.log(input);
        return [input.name ?? input.id, input.value];
      })
    );
    console.log(values);
  };
Slawa
  • 1,057
  • 13
  • 20
0

When you're using the method GET request type. You're already using the default method which would append the form data to the URL.

So, you'll get the select element's value appended along with the name.

However, if you want to dynamically change the URL. Then you can try it like:

function allvaluestostring() {
  var sts = document.getElementById("status").value;
  var size = document.getElementById("size").value;
  history.pushState("", "Title", "new_URL");
}

In the above statement, the values are stored in the variables and a history.pushState() method is called and it would change the string of the URL dynamically.

History API

Can I prevent history.popstate from triggering on initial page-load?

Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Afzaal Ahmad Zeeshan
  • 15,234
  • 11
  • 53
  • 100
  • Puropuse of form is to show results onchange by ajax, but on submit will do export selected data to the file. Export (when form is submited) is different function than showing results example. that means i dont need to change actual page url, but generate url for hthpprequest included page. – Martin Apr 17 '14 at 17:56
0

Dave's answer (https://stackoverflow.com/a/65383511/2740403) is perfect, but you need to extend it a little to work for multiselects...

    function getPlainObjectFromFormElement(form) {
    const elements = form.elements; 
    return Object.keys(elements).reduce((obj, field) => { 
        if (isNaN(field)) {

            // NEW SECTION
            if(elements[field].classList.contains("multiselect") ){ 
                var selected = [];
                for (var option of elements[field].options){
                    if (option.selected) {
                        selected.push(option.value);
                    }
                }
                obj[field] = selected.toString(); 
            // END NEW SECTION

            }else{
                obj[field] = elements[field].value;
            }
        }
        return obj;
    }, {});
}
Greggers
  • 131
  • 1
  • 6
0

2022 version

const formData = new URLSearchParams(new FormData(this));
Goddard
  • 2,418
  • 27
  • 35