How to compile multiple HMTL Form dropdown box values and send as one value to MYSQL table?

Viewed 34

I have an HTML form that has a simple item and #ofitems dropdown system. There are 3 dropdowns for items with a #ofitems dropdown next them. How would I go about compiling the form data into a value I can send to the table? I have seen a couple of people with different forms make a list of the items using a javascript add (or remove) button and then send this value to the table although their forms are just for same the item and does not also track the corresponding #ofitems.

Ideally I would like something coming back to the table like:

(flangeid) 1 x 3 (flangeid) 2 x 2

<div id="container">
            <form>
                <label for="flangeID">Flanges:</label>
                <select id="flangeID" name="flangeID" placeholder="flange">
                    <option value="1">Flange 1</option>
                    <option value="2">Flange 2</option>
                    <option value="3">Flange 3</option>
                    <option value="4">Flange 4</option>
                    <option value="5">Flange 5</option>
                <select>
                <label for="#ofitems">#ofitems:</label>
                <input type="number" id="#ofitems" min="0">
                <select id="flangeID" name="flangeID" placeholder="flange">
                      <option value="1">Flange 1</option>
                      <option value="2">Flange 2</option>
                      <option value="3">Flange 3</option>
                      <option value="4">Flange 4</option>
                      <option value="5">Flange 5</option>
                <select>
                <label for="#ofitems">#ofitems:</label>
                <input type="number" id="#ofitems" min="0">
                <select id="flangeID" name="flangeID" placeholder="flange">
                      <option value="1">Flange 1</option>
                      <option value="2">Flange 2</option>
                      <option value="3">Flange 3</option>
                      <option value="4">Flange 4</option>
                      <option value="5">Flange 5</option>
                <select>
                <label for="#ofitems">#ofitems:</label>
                <input type="number" id="#ofitems" min="0">
                <button id="btnAdd">Add Flange</button>
                <button id="btnRemove">Remove</button>
              </form>
          </div>
1 Answers

You can use FormData.getAll() to get an array of all values for a given key, where the key is the name of your form field. This allows you to use the same name for each select element you add or remove.

An example is listed below, but the relevant bit would be that in your submit handler you could do something like the following:

const form = document.getElementById("form");
const formData = new FormData(form);

// get an array of the values for each select element
const formData.getAll("flange");
// ...then do whatever work to save the values to DB etc.

Demo/Solution

In the example below, each select uses the name "flange" and a representation of getAll("flange") is shown on screen each time the form is updated.

Demo: https://codesandbox.io/s/formdata-getall-example-rjm6o5

JS

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

const formData = new FormData(form);

console.log("form values: ", formData.getAll("flange"));

const output = document.getElementById("output");

output.textContent = formData.getAll("flange")["0"];

const selectEl = document.getElementsByClassName("flange-select")[0];

selectEl.addEventListener("change", function () {
  getUpdatedFormValues();
});

const flangeOptions = [
  { value: 1, name: "Flange 1" },
  { value: 2, name: "Flange 2" },
  { value: 3, name: "Flange 3" },
  { value: 4, name: "Flange 4" },
  { value: 5, name: "Flange 5" }
];

function getUpdatedFormValues() {
  output.textContent = "";
  const newFormData = new FormData(form);
  console.log("updated form values: ", newFormData.getAll("flange"));
  output.textContent += newFormData.getAll("flange");
}

const button = document.getElementById("add-select");

button.addEventListener("click", function () {
  let newLabel = document.createElement("label");
  let selectEls = Object.values(
    document.getElementsByClassName("flange-select")
  );
  console.log(selectEls.length);
  newLabel.setAttribute("for", "flange-" + selectEls.length);
  let newSelect = document.createElement("select");
  newSelect.classList.add("flange-select");
  newSelect.setAttribute("name", "flange");
  newSelect.setAttribute("id", "flange-" + selectEls.length);
  newSelect.addEventListener("change", function () {
    getUpdatedFormValues();
  });
  flangeOptions.forEach((flange) => {
    let option = document.createElement("option");
    option.text = flange.name;
    option.value = flange.value;
    if (flange.value === 1) option.setAttribute("selected", true);
    newSelect.add(option);
  });

  button.parentNode.insertBefore(newLabel, button);
  button.parentNode.insertBefore(newSelect, button);

  getUpdatedFormValues();
});

HTML

<div id="app">
  <form id="form">
    <label for="flange-0">Flange: </label>
      <select class="flange-select" id="flange-0" name="flange">
         <option selected value="1">Flange 1</option>
         <option value="2">Flange 2</option>
         <option value="3">Flange 3</option>
         <option value="4">Flange 4</option>
         <option value="5">Flange 5</option>
      <select>
      <button type="button" id="add-select">Add select</button>
        <!-- 
          on submit, use getAll("flange") inside
          your submit handler...

          <button type="submit"></button> 
        
        -->
    </form>
  <output id="output"></output>
</div>

Explanation

The JS is a little verbose, but I wanted to provide a working example that demonstrates the shape of the form data changing based on adding a repeated list of fields, per your question.

[I've seen other solutions with forms reusing the same] item (NOTE: I read this as using the same input or field repeated within the form) and [there is also no need to] track the corresponding [number or ID of each item].

This sounds like you're asking for a list of values from the same field repeated in your form, but you're perhaps unsure if you need to do anything to order the fields or do anything on the frontend to keep track of each field separately.

getAll() helps by removing the need to uniquely or explicitly identify each field. The name attribute is all we need. Also, since you already use a select field to capture the selected option, the input seems unnecessary.

Instead of:

<input type="number" id="#ofitems" min="0">
  <select id="flangeID" name="flangeID" placeholder="flange">

You can just do:

<select id="flange-1" name="flange">

We use getAll("flange") to capture a list of the selected values from any fields with name="flange".

If the first field has Flange 3 selected, and the second field has Flange 2 selected, the array will have the following indexed values:

0: "3"
1: "2"

This should give you what you need. Any other logic you might require could be included when you process the form submission.

Related