skip to Main Content
<form>
    <input name="checkbox" type="checkbox"></input>
    <input name="value" type="text"></input>

    <input name="checkbox" type="checkbox"></input>

    <input name="value" type="text"></input>
... 
</form>

The user enters a phrase and indicates whether it is the correct answer. Is there any way to combine these into unique pairs when sending them so that they don’t get mixed up on the server?

At the moment, I solve it this way: when opening, a script is launched that runs through the passivity of the checkboxes and texts and combines the values of the text field and the checkbox into a string separated by "^". The problem is that user input can be anything and it looks like a terrible crutch.

2

Answers


  1. Group-by-name

    To group two (the checkbox’s and input’s) key-value pairs, they should have the same identifiable feature. You can give IDs to each group, and use it in the pairs’ keys to show their connection.

    Example:

    <form>
      <div>
        <input name="is-answer-1" type="checkbox">
        <input name="answer-1">
      </div>
      <div>
        <input name="is-answer-2" type="checkbox">
        <input name="answer-2">
      </div>
      <div>
        <input name="is-answer-3" type="checkbox">
        <input name="answer-3">
      </div>
    </form>

    If your backend is PHP, you may want to format your groups as follows:

    <form>
      <div>
        <input name="group[0][is-answer]" type="checkbox">
        <input name="group[0][answer]">
      </div>
      <div>
        <input name="group[1][is-answer]" type="checkbox">
        <input name="group[1][answer]">
      </div>
      <div>
        <input name="group[2][is-answer]" type="checkbox">
        <input name="group[2][answer]">
      </div>
    </form>

    This automatically provides the data as (associative) arrays in the expected format.

    Use JSON

    Should you not require the following navigation of a submission, you can also send the form data as JSON, e.g. via the Fetch API.

    JSON is a format for data transfer and pretty much universally supported. You may want to build the JSON manually for more control over the structure, instead of naively collecting the data as an array.

    Example:

    const form = document.forms[0];
    form.addEventListener("submit", evt => {
      evt.preventDefault(); // Do not submit-and-navigate; we "submit" manually
      
      // Collect form data as desired:
      const data = Array.from(form.elements)
        .filter(el => el.nodeName !== "BUTTON")
        .reduce((acc, el, i) => {
          const groupIndex = Math.floor(i / 2);
          const group = (acc[groupIndex] ??= {});
    
          if (i % 2 === 0) {
            // Checkbox
            group.isAnswer = el.checked;
          } else {
            // Input
            group.text = el.value;
          }
          return acc;
        }, []);
      
      // Convert to JSON
      const json = JSON.stringify(data);
      
      // See the JSON
      console.log(json);
      
      // Send (example):
      // fetch("http://example.com", { body: json });
    });
    <form>
      <div>
        <input type="checkbox">
        <input>
      </div>
      <div>
        <input type="checkbox">
        <input>
      </div>
      <div>
        <input type="checkbox">
        <input>
      </div>
      
      <button>Send</button>
    </form>

    Note: The example structures the form data manually, whereas the browser would require name attributes. This independece allows the omission of name, but for progressive enhancement the Group-by-name approach could additionally be applied.

    Use the order of fields

    Note: This is only included for completeness’ sake. Generally, I recommend the JSON or the first approach instead.

    Form fields are sent in tree order. This means (assuming all fields are sent), that the first is-answer (checkbox) and the first text (value) values are related, the second is-answer and the second text values, etc.

    But only checked checkboxes are sent, which means unchecked checkbox values would be dropped, destroying the order by shifting the following values.

    To keep the is-not-answer values from being dropped, "garbage" values have to be sent instead. A <select> may have two options, like a checkbox. Additionally, a <select>‘s value is always sent, making this a feasible alternative.

    Example:

    <form>
      <div>
        <select name="is-answer">
          <option value="false">Is not answer</option>
          <option value="true">Is answer</option>
        </select>
        <input name="text">
      </div>
      <div>
        <select name="is-answer">
          <option value="false">Is not answer</option>
          <option value="true">Is answer</option>
        </select>
        <input name="text">
      </div>
      <div>
        <select name="is-answer">
          <option value="false">Is not answer</option>
          <option value="true">Is answer</option>
        </select>
        <input name="text">
      </div>
    </form>
    Login or Signup to reply.
  2. I find the <fieldset> element to be a good way of structuring a form with repeating names/groups of form fields.

    In this example I send the values from each fieldset as a JSON string with a key named group_0, group_1 etc. If the backend is using PHP you could name the groups group[], group[] etc. for creating an array in PHP.

    This is somewhere in between sending the data as application/json and sending the data as multipart/form-data.

    document.forms.form01.addEventListener('submit', e => {
      e.preventDefault();
      let form = e.target;
      // create an empty form data object
      let data = new FormData();
      // loop all fieldsets
      [...form.group].forEach((group, i) => {
        // create an object for each fieldset
        let obj = [...group.elements].reduce((obj, input) => {
          obj[input.name] = (input.type == 'checkbox') ? input.checked : input.value;
          return obj;
        }, {});
        // add the stringify'ed object to the form data object
        data.set(`group_${i}`, JSON.stringify(obj));
      });
      // send the form data object
      fetch(form.action, {
        method: form.method,
        body: data
      });
    });
    <form name="form01" method="post" action="/endpoint">
      <fieldset name="group">
        <input name="checkbox" type="checkbox" value="test">
        <input name="value" type="text">
      </fieldset>
      <fieldset name="group">
        <input name="checkbox" type="checkbox">
        <input name="value" type="text">
      </fieldset>
      <fieldset name="group">
        <input name="checkbox" type="checkbox">
        <input name="value" type="text">
      </fieldset>
      <button>Submit</button>
    </form>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search