2

I'm trying to create a form that will show more fields based on what is selected in a dropdown menu. If 1 guest is selected, then 1 form appears. If 2, then 2 forms appears and so on.

I've managed to get the first Div (guestFormOne) to show/hide depending if 1 guest has been selected, but I'm struggling to find a solution to make this happen for up to 6 guests.

Here is what I have so far:

HTML

    <h4>Number of Guests</h4>
<select onchange="numofGuests()">
  <option>Select number of guests</option>
  <option id="guestCountOne">1</option>
  <option id="guestCountTwo">2</option>
  <option id="guestCountThree">3</option>
  <option id="guestCountFour">4</option>
  <option id="guestCountFive">5</option>
  <option id="guestCountSix">6</option>
</select>

<div id="guestFormOne">
  <h4>Guest 1</h4>
  <input type="text" placeholder="Name">
  <select id="guest1_meal">
   <option>Meal Choice</option>
   <option>Buffet</option>
   <option>Gluten Free</option>
   <option>Dairy Free</option>
   <option>Vegan</option>
  </select>

  <select id="guest1_age">
   <option>Age</option>
   <option>Adult</option>
   <option>Child under 5</option>
   <option>Child 6 - 12</option>
  </select>

  <input type="text" placeholder="Allergies?">
</div>

<div id="guestFormTwo">
  <h4>Guest 2</h4>
  <input type="text" placeholder="Name">
  <select id="guest2_meal">
   <option>Meal Choice</option>
   <option>Buffet</option>
   <option>Gluten Free</option>
   <option>Dairy Free</option>
   <option>Vegan</option>
  </select>

  <select id="guest2_age">
   <option>Age</option>
   <option>Adult</option>
   <option>Child under 5</option>
   <option>Child 6 - 12</option>
  </select>

  <input type="text" placeholder="Allergies?">
</div>

Javascript

   function numofGuests() {
      if (document.getElementById("guestCountOne").selected) {
        document.getElementById("guestFormOne").style.display = "block";
      } else {
        document.getElementById("guestFormOne").style.display = "none";
      }
    }

Help would be appreciated, as I feel like I'm stuck trying to get this to work.

Jdar
  • 35
  • 1
  • 4

4 Answers4

0

You would get all the hidden guest forms into a collection and then loop through that collection, unhiding them until you reach the count selected in the drop down. The guest forms don't need ids, you would just give them all the same CSS class. You would also set all of the guest forms to be hidden by default (using CSS a class as well, rather than with inline styles).

Lastly, don't use inline HTML event attributes (onchange, onclick, etc.). This is an ancient technique that causes many problems and needs to just die. Instead, do all your event binding in JavaScript.

var guestCount = document.getElementById("guestCount");
guestCount.addEventListener("change", numOfGuests);

// Get all the guest forms into an collection
var guestForms = document.querySelectorAll(".guestForm");


function numOfGuests() {
  // Loop through the guest forms based on the number selected
  guestForms.forEach(function(v,i){
    if(i < guestCount.value) {
      v.classList.remove("hidden");
    }
  });
}
.hidden { display:none; }
<h4>Number of Guests</h4>
<select id="guestCount">
  <option>Select number of guests</option>
  <option id="guestCountOne">1</option>
  <option id="guestCountTwo">2</option>
  <option id="guestCountThree">3</option>
  <option id="guestCountFour">4</option>
  <option id="guestCountFive">5</option>
  <option id="guestCountSix">6</option>
</select>

<div class="guestForm hidden">
  <h4>Guest 1</h4>
  <input type="text" placeholder="Name">
  <select id="guest1_meal">
   <option>Meal Choice</option>
   <option>Buffet</option>
   <option>Gluten Free</option>
   <option>Dairy Free</option>
   <option>Vegan</option>
  </select>

  <select id="guest1_age">
   <option>Age</option>
   <option>Adult</option>
   <option>Child under 5</option>
   <option>Child 6 - 12</option>
  </select>

  <input type="text" placeholder="Allergies?">
</div>

<div class="guestForm hidden">
  <h4>Guest 2</h4>
  <input type="text" placeholder="Name">
  <select id="guest2_meal">
   <option>Meal Choice</option>
   <option>Buffet</option>
   <option>Gluten Free</option>
   <option>Dairy Free</option>
   <option>Vegan</option>
  </select>

  <select id="guest2_age">
   <option>Age</option>
   <option>Adult</option>
   <option>Child under 5</option>
   <option>Child 6 - 12</option>
  </select>

  <input type="text" placeholder="Allergies?">
</div>

<div class="guestForm hidden">
  <h4>Guest 3</h4>
  <input type="text" placeholder="Name">
  <select id="guest2_meal">
   <option>Meal Choice</option>
   <option>Buffet</option>
   <option>Gluten Free</option>
   <option>Dairy Free</option>
   <option>Vegan</option>
  </select>

  <select id="guest2_age">
   <option>Age</option>
   <option>Adult</option>
   <option>Child under 5</option>
   <option>Child 6 - 12</option>
  </select>

  <input type="text" placeholder="Allergies?">
</div>

<div class="guestForm hidden">
  <h4>Guest 4</h4>
  <input type="text" placeholder="Name">
  <select id="guest2_meal">
   <option>Meal Choice</option>
   <option>Buffet</option>
   <option>Gluten Free</option>
   <option>Dairy Free</option>
   <option>Vegan</option>
  </select>

  <select id="guest2_age">
   <option>Age</option>
   <option>Adult</option>
   <option>Child under 5</option>
   <option>Child 6 - 12</option>
  </select>

  <input type="text" placeholder="Allergies?">
</div>

<div class="guestForm hidden">
  <h4>Guest 5</h4>
  <input type="text" placeholder="Name">
  <select id="guest2_meal">
   <option>Meal Choice</option>
   <option>Buffet</option>
   <option>Gluten Free</option>
   <option>Dairy Free</option>
   <option>Vegan</option>
  </select>

  <select id="guest2_age">
   <option>Age</option>
   <option>Adult</option>
   <option>Child under 5</option>
   <option>Child 6 - 12</option>
  </select>

  <input type="text" placeholder="Allergies?">
</div>

<div class="guestForm hidden">
  <h4>Guest 6</h4>
  <input type="text" placeholder="Name">
  <select id="guest2_meal">
   <option>Meal Choice</option>
   <option>Buffet</option>
   <option>Gluten Free</option>
   <option>Dairy Free</option>
   <option>Vegan</option>
  </select>

  <select id="guest2_age">
   <option>Age</option>
   <option>Adult</option>
   <option>Child under 5</option>
   <option>Child 6 - 12</option>
  </select>

  <input type="text" placeholder="Allergies?">
</div>

<div class="guestForm hidden">
  <h4>Guest 2</h4>
  <input type="text" placeholder="Name">
  <select id="guest2_meal">
   <option>Meal Choice</option>
   <option>Buffet</option>
   <option>Gluten Free</option>
   <option>Dairy Free</option>
   <option>Vegan</option>
  </select>

  <select id="guest2_age">
   <option>Age</option>
   <option>Adult</option>
   <option>Child under 5</option>
   <option>Child 6 - 12</option>
  </select>

  <input type="text" placeholder="Allergies?">
</div>

<div class="guestForm hidden">
  <h4>Guest 2</h4>
  <input type="text" placeholder="Name">
  <select id="guest2_meal">
   <option>Meal Choice</option>
   <option>Buffet</option>
   <option>Gluten Free</option>
   <option>Dairy Free</option>
   <option>Vegan</option>
  </select>

  <select id="guest2_age">
   <option>Age</option>
   <option>Adult</option>
   <option>Child under 5</option>
   <option>Child 6 - 12</option>
  </select>

  <input type="text" placeholder="Allergies?">
</div>

Now, having shown all that, really the best solution is to just dynamically create the guest forms on demand, instead of writing the same HTML over and over again:

var out = document.getElementById("output");
var guestCount = document.getElementById("guestCount");
guestCount.addEventListener("change", makeGuests);

function makeGuests(){

  out.innerHTML = ""; // Clear previous output
  
  // Set up arrays that hold data that the two guest form lists need:
  var meals = ["Meal Choice", "Buffet", "Gluten Free", "Dairy Free", "Vegan"];
  var ages = ["Age", "Adult", "Child under 5", "Child 6 - 12"];

  // Create a loop that iterates the numnber of times specified in the list
  for(var i = 0; i < guestCount.value; i++){
  
    // Create and configure a guest form, element by element...
    var container = document.createElement("div");
    
    var heading = document.createElement("h4");
    heading.textContent = "Guest " + (i + 1);
    container.appendChild(heading); // Put new element in container
    
    var txtName = document.createElement("input");
    txtName.type = "text"
    txtName.placeholder = "Name";
    txtName.name = "name";
    container.appendChild(txtName);
    
    var mealList = document.createElement("select");
    mealList.id = "guest" + (i + 1) + "_meal" ;
    // Loop through the meals array
    meals.forEach(function(value){
      // And, create an option for each one
      var opt = document.createElement("option");
      opt.textContent = value;
      mealList.appendChild(opt);
    });
    container.appendChild(mealList);
  
    var ageList = document.createElement("select");
    ageList.id = "guest" + (i + 1) + "_age" ;
    ages.forEach(function(value){
      var opt = document.createElement("option");
      opt.textContent = value;
      ageList.appendChild(opt);
    }); 
    container.appendChild(ageList);
  
    // Make final input
    var allergies = document.createElement("input");
    allergies.type = "text"
    allergies.placeholder = "Allergies?";
    container.appendChild(allergies);
  
    // Everything is made and in the container. Add the container to the document
    out.appendChild(container);
  }
}
.hidden { display:none; }
<h4>Number of Guests</h4>
<select id="guestCount">
  <option>Select number of guests</option>
  <option id="guestCountOne">1</option>
  <option id="guestCountTwo">2</option>
  <option id="guestCountThree">3</option>
  <option id="guestCountFour">4</option>
  <option id="guestCountFive">5</option>
  <option id="guestCountSix">6</option>
</select>

<div id="output"></div>
Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
0

Think a little different. And use following stratergy.

Hide all div first.

  1. Give id to div like guestForm1, guestForm2 etc.
  2. Pass id of dropdown to javascript and get its selected value
  3. Loop from the selectedValue as integer to 1 (or opposite) and find div with id=‘guestForm’+loopIndex.
  4. Make that div display block.

I can try to put some code together for this as example

Example

<select onchange='showForms(this)'>
<option value='0'>None</option>
 <option value='1'>1</option>
 <option value='2'>2</option>
 <option value='3'>3</option>
 <option value='4'>4</option>
 <option value='5'>5</option>
 <option value='6'>6</option>
</select>



<div id='guestForm1' style='display:none'>11</div>
<div id='guestForm2' style='display:none'>22</div>
<div id='guestForm3' style='display:none'>33</div>
<div id='guestForm4' style='display:none'>44</div>
<div id='guestForm5' style='display:none'>55</div>
<div id='guestForm6' style='display:none'>66</div>

Javascript

function showForms(dd)
{

    var ddVal=dd[dd.selectedIndex].value;

  for(i=1;i<=6;i++)
  {
     document.getElementById('guestForm'+i).style.display='none';
  }


  for(i=1;i<=ddVal;i++)
  {
     document.getElementById('guestForm'+i).style.display='block';
  }
}

Note, you still should add null checks, if div with certain id does not exist

SSD
  • 1,373
  • 2
  • 13
  • 20
0

You can add as many as you want, dynamically:

function numofGuests(val) {
    document.getElementById('guestFormOne').innerHTML = "";
    for (i = 0; i < parseInt(val.value); i++) { 
        document.getElementById('guestFormOne').innerHTML += '<h4>Guest '+(i+1)+'</h4><input type="text" placeholder="Name"><select  id="guest'+(i+1)+'_meal"><option>Meal Choice</option> <option>Buffet</option><option>Gluten Free</option><option>Dairy Free</option><option>Vegan</option></select><select id="guest'+(i+1)+'_age"><option>Age</option><option>Adult</option><option>Child under 5</option><option>Child 6 - 12</option></select><input type="text" placeholder="Allergies?">';
    }      
}    
<h4>Number of Guests</h4>
<select onchange="numofGuests(this)">
  <option>Select number of guests</option>
  <option>1</option>
  <option>2</option>
  <option>3</option>
  <option>4</option>
  <option>5</option>
  <option>6</option>
</select>

<div id="guestFormOne"></div>
Pedram
  • 828
  • 9
  • 24
0

There are few ways to start building an application. The following demo builds an application that does 2 jobs and is designed for expansion for additional functions if and when needed.

  • Listens for the click event on form#fX.

  • When clicked, it delegates the event between 2 buttons and ignores any other clicks.

  • The first job it does is generate a <fieldset> for each guest from a <template>. The number of guests is determined by the user input of input[type="number"]#qty. At this point, the input[type="submit"] button is revealed.

  • The second job is to submit the form data to a server. At this point a message is displayed informing user that the data has been sent and provides a link.

  • The link scrolls to iframe#view which displays the server's response.

  • This demo can do an unlimited amount of guests and each guest has a unique #id and all of its children nodes have unique [name] attributes.

Note: This demo sends data to a live test server.

References

Event Delegation

HTMLFormControlsCollection

Template Literals

<template> tag

Demo

var idx = 0;
var fX = document.forms.fX;
var Xf = fX.elements;

fX.addEventListener('click', delegateClick, false);

function delegateClick(e) {
  if (e.target !== e.currentTarget) {
    if (e.target.value === 'Process') {
      var qty = Xf.qty.valueAsNumber;
      idx = generateGuest(qty, idx);
      e.target.nextElementSibling.style.display = "inline-block";
    } else if (e.target.type === 'submit') {
      e.target.nextElementSibling.style.display = "block";
      Xf.msg.innerHTML = `Data sent. <a href='#view'>View response.</a>`;
    } else {
      return;
    }
  } else {
    return;
  }
}

function generateGuest(qty, idx) {
  var allx = idx + qty;
  for (idx; idx < allx; idx++) {
    var temp = document.getElementById('tmp');
    var cont = temp.content.getElementById('guest');
    var dupe = document.importNode(cont, true);
    var fset = Array.from(dupe.querySelectorAll('*'));
    dupe.id = `guest${idx}`;
    dupe.name = dupe.id;
    fset.map(function(node, index, fset) {
      fset[0].textContent = `Guest ${idx}`;
      fset[1].name = `nam${idx}`;
      fset[2].name = `eat${idx}`;
      fset[8].name = `med${idx}`;
      fset[9].name = `age${idx}`;
    });
    fX.appendChild(dupe);
  }
  return idx;
}
html {
  font: 400 16px/1.5 Consolas
}

fieldset {
  width: 65%
}

select,
input,
button,
output {
  font: inherit;
  display: inline-block
}

select,
input[type="text"] {
  width: 45%
}

select {
  padding: 4px
}

#qty {
  width: 5ch
}

input:not([type="text"]) {
  font-variant: small-caps
}

input[type="submit"],
#msg {
  display: none
}

#view {
  display: block;
  margin: 20px 0 0 0;
}
<form id='fX' action='https://httpbin.org/post' method='post' target='view'>

  <fieldset id='set'>
    <legend>Guest Register</legend>
    <input id='qty' type='number' min='1' max='99' value='1'>
    <input type='button' value='Process'>
    <input type='Submit'>
    <output id='msg'></output>
  </fieldset>
  <hr>
  <template id='tmp'>

  <fieldset id='guest' name='guest'>
    <legend>Guest&nbsp;</legend>
    <input name='nam' type="text" placeholder="Name">
    <select name='eat'>
   <option default>Diet</option>
   <option value='norm'>Buffet</option>
   <option value='tran'>Gluten Free</option>
   <option value='lact'>Dairy Free</option>
   <option value='vege'>Vegan</option>
  </select>
    <input name='med' type="text" placeholder="Allergies">
    <select name='age'>
   <option default>Age</option>
   <option value='18'>Adult</option>
   <option value='05'>Child under 5</option>
   <option value='12'>Child 6 - 12</option>
  </select>
  </fieldset>

  </template>

</form>

<iframe src='about:blank;' id='view' name='view' width='75%' height='75%' frameborder='0'></iframe>
Community
  • 1
  • 1
zer00ne
  • 41,936
  • 6
  • 41
  • 68