15

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.

4
  • A form doesn't change ? Commented Apr 17, 2014 at 17:42
  • use serialize with jQuery? Commented Apr 17, 2014 at 17:42
  • 1
    onsubmit, loop through and get the values... Commented Apr 17, 2014 at 17:42
  • adaneo: form is change, but i need to get all values from all input fields in form. Jason, i don't use jquery in this project. epascarello yes but I was hoping that there is exist some javascript included solution, I thought that is usual requirement. Commented Apr 17, 2014 at 17:49

11 Answers 11

30

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.

Sign up to request clarification or add additional context in comments.

2 Comments

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 you may want to use babel when coding es6 you know
15

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.

3 Comments

Put the function itself to the code, excelent solution!
This code is broken. having 3 <button> tags with the same name and different values will serialize all 3 buttons into the string instead of the one that was pressed.
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"].
13

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

Comments

6

this would likely be used when you attach an event to the form itself. I use the 'submit' event. Then this refers to the form itself.

2022 version

const formData = new URLSearchParams(new FormData(this));

1 Comment

Please specify this a bit further
3

As of late 2022, there is a better way to do this now, and it's supported by all modern browsers. Use the FormData constructor.

tldr;

console.log(Object.fromEntries(new FormData(form)));
// or
console.log(Object.fromEntries(new FormData(e.target)));

Example

Here is a full example of how to use the FormData constructor to get data from a form. You can see a live example here.

<!DOCTYPE html>
<html>
  <head>
    <title>FormData Example</title>
    <meta charset="UTF-8" />
  </head>

  <body>
    <form id="form">
      <input type="text" name="a" value="foo" />
      <input type="text" name="b" value="bar" />
      <input type="text" name="c" value="baz" />
      <input type="checkbox" name="check" checked disabled />
      <button>Submit</button>
    </form>

    <script>
      const form = document.getElementById("form");

      form.addEventListener("submit", (e) => {
        // this is used only for this example, 
        // to prevent submission of the form
        // so you can inspect the data below
        e.preventDefault();

        // you can pass "form" or "e.target" to FormData
        console.log(Object.fromEntries(new FormData(e.target)));
        console.log(Object.fromEntries(new FormData(form)));
        // { a: "foo", b: "bar", c: "baz" }
      });
    </script>
  </body>
</html>

Comments

2

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

Comments

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

Comments

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?

1 Comment

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.
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;
    }, {});
}

Comments

0

2023 Version

(Since we're naming years here lol)

function onSubmit(e: Event) {

  const form = new FormData(e.target as HTMLFormElement);
  const { name, email } = Object.fromEntries(form);

  // do something with data

}

Here is an example with the Record type assuming a key / value both of type string:

const { name } = Object.fromEntries(form) as Record<string, string>;

J

5 Comments

This solution is quite elegant. But how to append new pairs of key/value in a such element. form.append(k, v) throws an error
It should work fine, you must have some other error - svelte.dev/repl/605e37fb97184f608a39190fb1f51087?version=3.55.1
Indeed! it's just that formData looks like an empty dict and when I try to JSON stringify it, it returns an empty string. Seems that you can't add formData as body in a fetch method. Here, what I'm trying to do svelte.dev/repl/a3c5e2545d4d47c3922539194942716d?version=3.55.1
I'm not sure what you're trying to do, but probably not appropriate for this question. I suggest you create a new question with a full example repo (not svelte) demonstrating your problem.
Thanks, you're right. I have a better understanding now of my mistakes now.
0

If you want all elements with certain class (example: step1):

var dataform = new FormData;
 var elemSteps = document.querySelectorAll('#frm-checkout .step1');
 elemSteps.forEach(elemStep => {
     dataform.append(elemStep.getAttribute('name'), elemStep.value)
 });
  var params = new URLSearchParams(dataform);
 params = params.toString();

//to get all data
var form = document.getElementById('frm-checkout');
 var dataform = new FormData(form); 
  var params = new URLSearchParams(dataform);
 params = params.toString();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.