0

Hi I have a multiple step form, divided by .step-box. I don't want the user to get to the next step when fields are left empty. So that when you click on .next, that the form will show which fields are still required. I can access all inputs,selects,radios and checkboxes via stepBoxes[stepIndex].querySelectorAll('input, select').

const nextBtns = document.querySelectorAll('.next-btn');
const stepBoxes = document.querySelectorAll('.step-box');
const backBtn = document.querySelector('.back-btn');
const stepCircles = document.querySelectorAll('.step-circle');
let stepIndex = 0;

nextBtns?.forEach((nextBtn) => {
    nextBtn.addEventListener('click', (e) => {
        e.preventDefault();
        stepBoxes[stepIndex].classList.add('hide');
        let inputs = stepBoxes[stepIndex].querySelectorAll('input, select');
        
        stepCircles[stepIndex].classList.remove('active');
        stepIndex++;
        stepBoxes[stepIndex].classList.remove('hide');
        stepCircles[stepIndex].classList.add('active');
        backBtn.classList.toggle("hide", stepIndex == 0);
    });
});

I tried looping through the fields per step which kinda worked out with a select and a regular text input field. just by looping through them and adding an .invalid class to the ones which are required. It worked out for the regular inputs and select boxes, but not for the radios/checkboxes. Since you've got multiple per item.

I was wondering if someone had a vanilla JS idea on how to do this in a proper way.

Specific text inputs, select boxes and radio groups need to be required. For checkboxes I don't really mind since those are optional.

EDIT:

I currently created a specific form per step, where I added the required attribute to the required fields.

const membershipForm = document.getElementById('membershipForm');

membershipForm?.addEventListener('submit', (e) => {
    e.preventDefault();
    const formData = new FormData(membershipForm);
    for (const pair of formData.entries()) {
        jsonObject[pair[0]] = pair[1];
    }
    console.log(jsonObject);
});
Jorn Reed
  • 35
  • 5
  • Why not make the fields "required" ? then no JS needed. Make sure the select's first option is value="". [Here is how to make radios required](https://stackoverflow.com/questions/8287779/how-to-use-the-required-attribute-with-a-radio-input-field) – mplungjan Mar 28 '23 at 07:33
  • @mplungjan that only option would work when you click on the actual submit button in the end right? Cause I don't want users to get to the next step, when required fields are still empty – Jorn Reed Mar 28 '23 at 07:36
  • Make each step a form and gather the values in an array and have the last submit ajax the results – mplungjan Mar 28 '23 at 07:36
  • 1
    @mplungjan that sounds do-able. And easy, I'll give it a try! – Jorn Reed Mar 28 '23 at 07:39
  • @mplungjan I currently trying it with the first step https://pastebin.com/Q0zH7baq Although nothing seems to be logging in the console. – Jorn Reed Mar 28 '23 at 07:50
  • You can click [edit] and then `[<>]` snippet editor here at SO - I do not see a running version in the pastebin – mplungjan Mar 28 '23 at 07:57
  • Please make a [mcve] here – mplungjan Mar 28 '23 at 07:58

1 Answers1

1

Here is a simple example

I assume you can figure out to add a prev

const result = [];
const formDiv = document.getElementById('forms');
const forms = formDiv.querySelectorAll('form');
let currentForm = 0;
formDiv.addEventListener('submit', (e) => {
  e.preventDefault();
  const tgt = e.target;
  const formData = new FormData(tgt);
  result[currentForm] = Object.fromEntries(formData);
  console.log(result);
  currentForm++;
  if (currentForm===forms.length) {
    console.log("submit",result)
    return
  }
  let nextForm = forms[currentForm];
  tgt.hidden = true;
  nextForm.hidden = false;  
});
<div id="forms">
  <form id="form1" class="form">
    <input type="text" name="field1" placeholder="Field1" value="" required />
    <label><input type="radio" name="radio1" value="yes" required>Yes</label>
    <label><input type="radio" name="radio1" value="no">No</label>
    <input type="submit" value="next"/>
  </form>
  <form id="form2" class="form" hidden>
    <input type="text" name="field2" placeholder="Field2" value="" required />
    <label><input type="radio" name="radio2" value="yes" required>Yes</label>
    <label><input type="radio" name="radio2" value="no">No</label>
    <input type="submit" value="next" />
  </form>
  <form id="form3" class="form" hidden>
    <input type="text" name="field3" placeholder="Field3" value="" required />
    <label><input type="radio" name="radio3" value="yes" required>Yes</label>
    <label><input type="radio" name="radio3" value="no">No</label>
    <input type="submit" value="next" />
  </form>
</div>
mplungjan
  • 169,008
  • 28
  • 173
  • 236
  • that is exactly how I am doing it now. although I use the hide form way a bit like my old way, which fits in fine. I did not know that `hidden` was a form attribute. But you're way worked! – Jorn Reed Mar 28 '23 at 08:24
  • Since I'm using the basic html/js validation way, is it easy to add an `.invalid` class to to empty required fields? – Jorn Reed Mar 28 '23 at 08:29
  • https://stackoverflow.com/questions/70233435/check-validity-and-apply-style-when-user-leaves-the-field – mplungjan Mar 28 '23 at 08:32
  • that does work, but already applies the invalid styling to it when the form loads – Jorn Reed Mar 28 '23 at 08:36
  • Have a play around with this - I do not have time right now: https://stackoverflow.com/questions/27021801/inputinvalid-css-rule-is-applied-on-page-load – mplungjan Mar 28 '23 at 08:44