Home > other >  What is the closest solution to this Idea/Problem I have with forms in HTML?
What is the closest solution to this Idea/Problem I have with forms in HTML?

Time:01-02

I want to make a select form in HTML that checks that displays a secondary select group if certain options in the first select group are selected

<body>
    <form name="Test">
        <!-- all the factors to account for when calculating odds-->
        <div>
            <label>
            <select name="FirstList" id="FirstListID">
                <option value="1">First option</option>
                <option value="2">Second option</option>
                <option value="3">Third option</option>
            </select><br>
                
            <!-- SecondList would be visible if "1" is selected-->
            <label name="SecondList" style="display:none">List for "1":
                <select name="SecondListSelect" id="SecondListSelectID">
                    <option value="3">Placeholder</option>
                </select><br>
            </label>
            <!-- ThirdList would be visible if "2" is selected-->
            <label name="ThirdList" style="display:none">List for "2":
                <select name="ThirdListSelect" id="ThirdListSelectID">
                    <option value="4">Placeholder</option>
                </select><br>
            </label>
            <!-- No secondary select form appears if "3" is selected-->
        </div>
    </form>
</body>

I've tried using AddEventListeners but the code doesn't appear that maintainable since I plan on adding more options in the primary drop down menu so I would need to constantly add what secondary select groups appear based on what primary option is selected. How could I go about coding this in JS?

CodePudding user response:

Give each <label> an identifier tying it to the value for which it should be visible. A data attribute would work. Then, whenever the <select> changes, iterate over all such labels and hide them. Take the .value from the select and use string concatenation to construct a selector for the element with that in the dataset, and then you can select that element and show it.

For example, with labels like

<label data-option=1>

you could have

for (const label of document.querySelectorAll('[data-option]')) {
  label.style.display = 'none';
}
document.querySelector(`[data-option=${select.value}]`).style.display = 'block';

inside the change listener.

CodePudding user response:

Store the options of the second <select> element in an object. Make sure the keys match the value attribute value of the options in the first <select>.

Listen for a change event on the first <select>. Whenever a change happens, empty the options of the second <select>, get the new options from the object and create new <option> elements with that data.

Now you have a dynamic <select> element that is easy to scale.

const optionData = {
  '1': [
    {
      label: 'Foo',
      value: 'foo',
    }
  ],
  '2': [
    {
      label: 'Bar',
      value: 'bar',
    },
    {
      label: 'Baz',
      value: 'baz',
    }
  ],
  '3': [
    {
      label: 'Hello',
      value: 'hello',
    },
    {
      label: 'World',
      value: 'world',
    }
  ]
};

const firstList = document.querySelector('#first-list');
const secondList = document.querySelector('#second-list');

function removeOptions(selectElement) {
  for (let i = selectElement.options.length - 1; i >= 0; i--) {
    selectElement.remove(i);
  }
}

// Update the second `<select>` based on the first's selection.
firstList.addEventListener('change', event => {
  const value = event.target.value;
  const options = optionData[value];
  
  removeOptions(secondList);
  
  for (const { label, value } of options) {
    const option = new Option(label, value);
    secondList.add(option);
  }
});
<label for="first-list">List One</label>
<select name="first-list" id="first-list">
  <option value="" selected disabled>Make a selection</option>
  <option value="1">First option</option>
  <option value="2">Second option</option>
  <option value="3">Third option</option>
</select>

<label for="second-list">List Two</label>
<select name="second-list" id="second-list">
  <option value="" selected disabled>No options yet</option>
</select>

CodePudding user response:

You could build the selectors from your js file:

const optionGroups = {
      "first": [
        { "text": "for first - 1", "value": 1 }
      ],
      "second": [
        { "text": "for second - 1", "value": 1 },
        { "text": "for second - 2", "value": 2 }
      ],
      "third": [
        { "text": "for third - 1", "value": 1 },
        { "text": "for third - 2", "value": 2 },
        { "text": "for third - 3", "value": 3 }
      ]
    },
      mainSelect = document.querySelector('#mainSelect'),
      secondarySelect = document.querySelector('#secondarySelect');

async function startWithMainSelect()
{
  for (let key of Object.keys(optionGroups))
  {
    const option = new Option(key);
    mainSelect.appendChild(option);
  }

  onChangeMainSelect();
}

function onChangeMainSelect()
{
  while (secondarySelect.firstChild)
    secondarySelect.firstChild.remove();

  for (let _option of optionGroups[mainSelect.value])
  {
    const option = new Option(_option.text, _option.value);
    secondarySelect.appendChild(option);
  }
}

mainSelect.addEventListener('change', onChangeMainSelect);

startWithMainSelect();
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>replit</title>
  <link href="style.css" rel="stylesheet" type="text/css" />
</head>

<body>

  <h4>Main:</h4>

  <select id="mainSelect"></select>

  <br>

  <h4>Secondary:</h4>

  <select id="secondarySelect"></select>


  <script src="https://replit.com/public/js/replit-badge.js" theme="blue" defer></script>
  <script src="script.js"></script>
</body>

</html>

If there were a lot of options, you could move them into a json file and request them from there. Here's an example.

  • Related