4

i'm trying to pull out all of the data from my form and convert it to a queryString, to then post to an endpoint.

This is what I have so far, however I can#t figure out a quick and clean way to convert this to for example: key=value&key=value.

let data = Array.from(this.querySelectorAll('input:not([type="submit"]), select, textarea')).map(input => {
    let value = '';
    switch(input.tagName) {
        case 'INPUT':
            value = input.value;
            break;
        case 'SELECT':
            value = input[input.selectedIndex].value;
            break;
        case 'TEXTAREA':
            value = input.innerHTML;
            break;
    }

    return {
        key: input.name,
        value: value
    };
});

console.log(data);

// Object.keys(obj).map(k => `${encodeURIComponent(k)}=${encodeURIComponent(obj[k])}`).join('&');

The above code is creating an array of objects, with the key and values. It would be nice to be able use the one liner which is commented out above.

Martyn Ball
  • 4,679
  • 8
  • 56
  • 126
  • 3
    You don't need that `switch`. `this.value` will work in all three cases. – Andreas Jul 17 '19 at 11:51
  • https://stackoverflow.com/questions/41431322/how-to-convert-formdatahtml5-object-to-json – NoOorZ24 Jul 17 '19 at 11:53
  • 1
    Using `.innerHTML` for ` – Pointy Jul 17 '19 at 11:55
  • https://stackoverflow.com/questions/11661187/form-serialize-javascript-no-framework – acrazing Jul 17 '19 at 11:58
  • 2
    `be nice to be able use the one liner` -> `data.map(({key, value}) => \`${encodeURIComponent(key)}=${encodeURIComponent(value)}\`).join('&');` – Keith Jul 17 '19 at 12:02

2 Answers2

9

Scrap what you got. You should wrap your inputs in a <form>. Not only is this semantically correct, but it allows you to get a FormData object from the form. See my code:

const form = document.getElementById('my-form');

form.addEventListener('submit', (evt) => {
  evt.preventDefault();
  const formData = new FormData(form);
  const params = new URLSearchParams(formData);
  console.log(params.toString());
});
<form id="my-form">
  <input type="text" name="name" id="name">
  <select id="gender" name="gender">
    <option value="foo">Foo</option>
    <option value="bar">Bar</option>
    <option value="baz">Baz</option>
  </select>
  <input type="submit" />
</form>

FormData objects can also be given directly to the body of a fetch-request. No need to construct the query string yourself.

You can add or remove different input fields from the code above, and it will still work.

Phillip
  • 6,033
  • 3
  • 24
  • 34
  • I tried FormData but it wouldn't work for me, and I also get a warning saying that `FormData` expects 0 parameters, but thanks, this works! – Martyn Ball Jul 17 '19 at 12:03
1

You could use URLSearchParams interface to transform a FormData interface into a query string

Please try this example

const form = document.forms.form;

form.addEventListener("submit", handleSubmit);

function handleSubmit(event) {
  event.preventDefault();

  const formData = new FormData(form);
  const queryString = new URLSearchParams(formData).toString();

  console.log(queryString);
}
label, input, select, textarea {
  display: block;
}
<form action="" name="form" id="form">
  <label for="firstName">
    First name
    <input type="text" name="firstName" id="firstName" />
  </label>

  <label for="lastName">
    Last name
    <input type="text" name="lastName" id="lastName" />
  </label>

  <label for="email">
    Email
    <input type="text" name="email" id="email" />
  </label>

  <label for="genre">
    Genre
    <select name="genre" id="genre">
      <option value="female">Female</option>
      <option value="male">Male</option>
    </select>
  </label>

  <label for="bio">
    Bio
    <textarea name="bio" id="bio" cols="30" rows="10"></textarea>
  </label>

  <p>
    <button type="submit">Submit</button>
  </p>
</form>
Mario
  • 4,784
  • 3
  • 34
  • 50