Generate HTML so that second dropdown can be based on selected value of first dropdown

I’m looking for help with populating a second dropdown based on what’s selected in the first dropdown.

I have this code on an html page to test, but when “a” appears in the first dropdown, and then I select the second dropdown, it displays all choices instead of just the “a” choices (which are just a b and c).

<select name="test1" id="test1">
   <option value="Select">Select</option>
   <option value="a">a</option>
   <option value="b">b</option>
</select>


<select id="test2" name="test2">
<option value="Select">Select</option>
   <option value="a">a</option>
   <option value="a">b</option>
   <option value="a">c</option>
   <option value="b">1</option>
   <option value="b">2</option>
   <option value="b">3</option>
 </select>
jQuery(document).ready(function($){
    var options = $('#test2 option');
    $('#test1').on('change', function(e){
        $('#test2').append(options);
        if($(this).val() != 'Select') {
             $('#test2 option[value!=' + $(this).val() +']').remove();
        } else {
            $('#test2').val('Select');
        }

    });
});

Any help with getting the ‘a’ selection to just display ‘a’ choices and the ‘b’ selection to just show ‘b’ choices, is appreciated.

I would leave the unused options there so that you can get them back again when the person changes their mind. You can’t hide options due to some browser compatibility issues, but you can certainly mark them as disabled and use CSS to hide them.

select option[disabled] {
    display: none;
}

All you need to do is to first disable all of the #test2 options, then enable only the ones that match the type of class you want.

jQuery(document).ready(function($){
    $('#test1').on('change', function(e){
        var className = e.target.value;
        $('#test2 option').prop('disabled', true);
        $('#test2').find('option.' + className).prop('disabled', false);
    });
});

Many thanks for your reply and advice, however it appears to me that your jsfiddle has the same issue, it displays all choices instead of just the “a” choices. And the ‘b’ choice displays all choices not just the ‘b’ choices.

That’s just because jQuery wasn’t installed. When transferring working code to jsfiddle I failed to add the jQuery resource. The updated link has jQuery and works.

I would consider this the kind of thing you would want to tackle using AJAX, jQuery or otherwise.

If that’s not an option you could script it like this:

		<select name="test1" id="test1" class="red">
   <option value="Select" >Select</option>
   <option value="a">a</option>
   <option value="b">b</option>
</select>


<select id="test2" name="test2">
<option value="Select">Select</option>
 </select>

	</body>
	
	<script>
jQuery(document).ready(function($){
    var optionSets ={
	    a:['a','b','c'],
		b:['1','2','3'],
		x:['1a','2b','3c']
    }
    { 
     	let appendString ='<option value="Select">Select</option>';
        for (let opt  in optionSets){  appendString+= '<option value="'+opt+'">'+opt+'</option>'}
    	$('#test1').html(appendString);
    }
    $('#test1').on('change', function (e)  {
	    let selectedGroup = this.value;
 	    let optGroup = optionSets[selectedGroup];
	    let appendString ='<option value="Select">Select</option>';
	    if (selectedGroup) { optGroup.forEach(val => appendString+= '<option value="'+selectedGroup+'">'+val+'</option>')}
	    $('#test2').html(appendString);
    });
});
</script>

hope that helps

Thanks for your replies. I would be interested in use AJAX, but am not too vered in that.
However, currently when I add your code to an html page I still see all options upon selection. And also, when I add Paul’s code same result. I see that it works in https://jsfiddle.net/7zfo93bh/ so I don’t know what I could be doing wrong. Any ideas are appreciated.

Can you link us to your page so that we may investigate? If not, the full HTML code would certainly be handy.

Thanks for your reply here’s the full code test page:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="utf-8">
	<meta name="viewport"    content="width=device-width, initial-scale=1.0">
	<meta name="description" content="">
	<meta name="author"      content="">
	<meta name="keywords" content="" />
	<title></title>
<style>
select option[disabled] {
    display: none;
}
</style>

<script>
jQuery(document).ready(function($){
    $('#test1').on('change', function(e){
        var className = e.target.value;
        $('#test2 option').prop('disabled', true);
        $('#test2').find('option.' + className).prop('disabled', false);
    });
});
</script>
</head>
<body>
<select name="test1" id="test1">
   <option value="Select">Select</option>
   <option value="a">a</option>
   <option value="b">b</option>
</select>
<select id="test2" name="test2">
<option value="Select">Select</option>
   <option class="a" value="a">a</option>
   <option class="a" value="b">b</option>
   <option class="a" value="c">c</option>
   <option class="b" value="1">1</option>
   <option class="b" value="2">2</option>
   <option class="b" value="3">3</option>
 </select>

</body>
</html>

I look forward to any comments

I don’t see in your HTML code where jQuery is being loaded. Is it possible that you forgot to do that?

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

Thanks, of course I missed that. Much appreciated.
Ultimately, I’m trying to learn/add a second dropdown to an existing web script’s inital dropdown. Which shows this in the Form:

<div class="form-group">
<label class="col-md-12" for="category_id">{{LANG category}}</label>
<div class="col-md-12">
<select name="category_id" id="category_id" class="form-control">
<?php foreach($pt->categories as $key => $category) {?>
<option value="<?php echo $key?>"><?php echo $category?></option>
<?php } ?>
</select>
</div>
</div>

So, to begin, I’m trying to add an option of the secondary dropdown. So maybe something like:


<select name="category_id" id="category_id" class="form-control">
<?php foreach($pt->categories as $key => $category) {?>
<option value="<?php echo $key?>"><?php echo $category?></option>
<option value="<?php echo $key?>"><?php echo $category2?></option>
</select>
<div class="form-group">
<label class="col-md-12" for="category_id">{{LANG category2}}</label>
<div class="col-md-12">
<select id="category2" name="category2">
<option value="<?php echo $key?>"><?php echo $category2?></option>
<option value="<?php echo $key?>"><?php echo $category2?></option>
<option value="<?php echo $key?>"><?php echo $category2?></option>
<?php } ?>
</select>

I look forward to being further enlightened. Much thanks again.

This is where I redirect things to the PHP forum, as they are much better at dealing with that side of things.

One way I often handle this is to just POST the form when the first selection is made. I do this by adding this small bit of code to the first SELECT tag.

 onchange="this.form.submit()"

I build an array with categories and subcategories, so the Category is the Primary KEY followed by an array holding the Subcategories under this Category. It would look something like this.

Array
(
    [a] => Array
        (
            [a1] => a1
            [a2] => a2
            [a3] => a3
        )

    [b] => Array
        (
            [b1] => b1
            [b2] => b2
            [b3] => b3
        )
)

I would usually build this array within a WHILE query result loop something like this.

$select_options[$row['category']][$row['subcategory_id']] = $row['subcategoryname'];

You can them loop through the array while building the form and check for $_POST['category_id'] and if “NOT EMPTY” and “ARRAY KEY EXISTS” you can then loop through these Subcategories.

You’ll want to have a check for POST to set the the selected option as selected so it is still selected as the page reloads.

$selected_cat = (!empty($_POST['category_id']) && $_POST['category_id'] == $category ? ' selected="selected"' : '');
<div class="form-group">
		<label class="col-md-12" for="category_id">{{LANG category}}</label>
		<div class="col-md-12">
			<select name="category_id" id="category_id" class="form-control" onchange="this.form.submit()">
			<option value="Select">Select</option>
			<?php
			if(!empty($select_options)):
				foreach($select_options as $category => $subcategories):
					$selected_cat = (!empty($_POST['category_id']) && $_POST['category_id'] == $category ? ' selected="selected"' : ''); 
					echo '<option value="'.$category.'"'.$selected_cat.'>'.$category.'</option>'."\r";
				endforeach;
			endif;
			?>
			</select>
		</div>
		<label class="col-md-12" for="subcategory_id">{{SUB category}}</label>
		<div class="col-md-12">
			<select name="subcategory_id" id="subcategory_id" class="form-control">
			<option value="Select">Select</option>
			<?php
			if(!empty($select_options) && !empty($_POST['category_id']) && array_key_exists($_POST['category_id'],$select_options)):
				foreach($select_options[$_POST['category_id']] as $subcategory_id => $subcategoryname):  
					echo '<option value="'.$subcategory_id.'">'.$subcategoryname.'</option>'."\r";
				endforeach;
			endif;
			?>
			</select>
		</div>	
	</div>

If you really need both IDs and Names for both Categories and Subcategories you can ADD these hard coded Keys to your array build and adjust your form building to accommodate.

Array
(
    [a] => Array
        (
            [name] => category a
            [subcategories] => Array
                (
                    [a1] => subcategory a1
                    [a2] => subcategory a2
                    [a3] => subcategory a3
                )

        )

    [b] => Array
        (
            [name] => category b
            [subcategories] => Array
                (
                    [b1] => subcategory b1
                    [b2] => subcategory b2
                    [b3] => subcategory b3
                )

        )

)

You would build this array using 2 lines like this.

$select_options2[$row['category_id']]['name'] = $row['category'];
$select_options2[$row['category_id']]['subcategories'][$row['subcategory_id']] = $row['subcategoryname'];

The form build would then use these ‘name’ and ‘subcategories’ keys.

<div class="form-group">
		<label class="col-md-12" for="category_id">{{LANG category}}</label>
		<div class="col-md-12">
			<select name="category_id" id="category_id" class="form-control" onchange="this.form.submit()">
			<option value="Select">Select</option>
			<?php
			if(!empty($select_options2)):
				foreach($select_options2 as $category_id => $subcategories): 	  
					$selected_cat = (!empty($_POST['category_id']) && $_POST['category_id'] == $category_id ? ' selected="selected"' : ''); 
					echo '<option value="'.$category_id.'"'.$selected_cat.'>'.$select_options2[$category_id]['name'].'</option>'."\r";
				endforeach;
			endif;
			?>
			</select>
		</div>
		<label class="col-md-12" for="subcategory_id">{{SUB category}}</label>
		<div class="col-md-12">
			<select name="subcategory_id" id="subcategory_id" class="form-control">
			<option value="Select">Select</option>
			<?php
			if(!empty($select_options2) && !empty($_POST['category_id']) && array_key_exists($_POST['category_id'],$select_options2)):
				foreach($select_options2[$_POST['category_id']]['subcategories'] as $subcategory_id => $subcategoryname):  
					echo '<option value="'.$subcategory_id.'">'.$subcategoryname.'</option>'."\r";
				endforeach;
			endif;
			?>
			</select>
		</div>	
	</div>

There are other ways to do this with jQuey and hiding options etc but I find this works well in a lot of cases.

Thank you for your reply.
I am testing your code. But, an intial question is would this code work being that the Category code that I posted in #10, in this thread, has info already working and coming from a db?

What does the results look like?
Put it in pre print to view array structure like I did in my example.

echo "<pre>";
print_r($pt->categories);
echo "</pre>";	

Does it contain category and subcategory fields with corresponding ids like rows of data?
If so, you should be able to loop through it and build the array.

Here is my approach:

<!DOCTYPE html>
<html id="html">
<head>
<meta charset="UTF-8">
<title>Two Selects</title>
<style type="text/css">
select{display:block; margin:10px;}
</style>
</head>
<body>
<select id="select1">
  <option disabled>Select....</option>
  <option value="metal">Metal</option>
  <option value="gas">Gas</option>
</select>
<select id="select2">
  <option disabled>Select above first</option>
</select>
<script>
var firstSelect = document.getElementById("select1");
var secondSelect = document.getElementById("select2");

firstSelect.addEventListener("change",update);
firstSelect.selectedIndex = 0;
secondSelect.selectedIndex = 0;

function update(){
	var selection = document.getElementById("select1").value;
	
	var xmlhttp = new XMLHttpRequest();
	xmlhttp.onreadystatechange = function(){
		if (this.readyState == 4 && this.status == 200){
			document.getElementById("select2").innerHTML = this.responseText;
			secondSelect.selectedIndex = 0;
		}
	}
	xmlhttp.open("GET", "second.php?" + selection, true);
	xmlhttp.send();
}
</script>
</body>
</html>

And PHP file ‘second.php’:

<option disabled>Select....</option>
<?php
if($_SERVER['QUERY_STRING']=="metal")
{?>
<option>Iron</option>
<option>Aluminium</option>
<option>Brass</option>
<?php
}
if($_SERVER['QUERY_STRING']=="gas")
{?>
<option>Oxygen</option>
<option>Nitrogen</option>
<option>Carbon Dioxide</option>
<?php
}
?>

Demonstrated here (on free webspace):
http://flexi.epizy.com/selects.html

Of course the PHP file could get the options by searching a database with the URL’s query string.

Thanks for the help:
I put all of your code on the html page to test like so:

<select id="select1">
<option disabled>Select....</option>
<option value="metal">Metal</option>
<option value="gas">Gas</option>
</select>
<select id="select2">
 <option disabled>Select above first</option>
</select>

<option disabled>Select....</option>

<?php
if($_SERVER['QUERY_STRING']=="metal")
{?>
<option>Iron</option>
<option>Aluminium</option>
<option>Brass</option>
<?php
}
if($_SERVER['QUERY_STRING']=="gas")
{?>
<option>Oxygen</option>
<option>Nitrogen</option>
<option>Carbon Dioxide</option>
<?php
}
?>

<script>
var firstSelect = document.getElementById("select1");
var secondSelect = document.getElementById("select2");

firstSelect.addEventListener("change",update);
firstSelect.selectedIndex = 0;
secondSelect.selectedIndex = 0;

function update(){
	var selection = document.getElementById("select1").value;

	var xmlhttp = new XMLHttpRequest();
	xmlhttp.onreadystatechange = function(){
		if (this.readyState == 4 && this.status == 200){
			document.getElementById("select2").innerHTML = this.responseText;
			secondSelect.selectedIndex = 0;
		}
	}
	xmlhttp.open("GET", "second.php?" + selection, true);
	xmlhttp.send();
}
</script>

And although I see it works successfully in your provided link, no Second drop down list appeared after selecting the First drop down choices on my page.

Any additional guidance is welcomed.

I have two files on the server:

  • selects.html that provides the initial web page
  • second.php that provides data to update the initial web page.

AJAX allows you to get data from a server without reloading the page. You need a file on the server to provide the data.

For my demonstration of choosing either metals or gases, I would normally use just one HTML file and simply hide the metal and gas options until a selection was made in the first <select> element. JavaScript would be used to show the appropriate options for the second <select> element one way or another.

AJAX is more useful if you need to get the options for the second <select> element by searching a database.

I used one file to provide the data and used a URL search string to determine what data is sent from the server after the first selection is made. You can click on:
http://flexi.epizy.com/second.php?metal
or:
http://flexi.epizy.com/second.php?gas
and use ‘View Source’ in your browser to see what data is sent. In this case the data is the innerHTML needed for the second <select> element: in other words the HTML for the <option> elements.

I could have used more than one file to provide data to update the initial web page, say metal.html and gas.html. I chose to use the URL search string approach because potentially the search string can be used for a database search. When the AJAX request is made, the file on the server needs to get the search string from the URL and respond accordingly. This means that the file has to be PHP.

You may find this helpful:
https://www.w3schools.com/js/js_ajax_intro.asp
(the code for the XMLHttpRequest is rather difficult to understand!)

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.