There are a number of ways to do this - all involving Javascript - but the most elegant way is to use AJAX. This allows the client to retrieve the new list of subcategories without reloading the entire page. I did this just the other day, actually. Here's my code; you'll need to alter the updateItems() function to fit your situation:
<?php
define( "DB_HOST", "myhostname" );
define( "DB_NAME", "mydbname" );
define( "DB_USER", "mydbusername" );
define( "DB_PASS", "mydbpassword" );
$dbconn = mysql_connect( DB_HOST, DB_USER, DB_PASS );
mysql_select_db( DB_NAME, $dbconn );
?>
<html>
<head>
<title></title>
<script>
function HttpRequest( url ) {
var pageRequest = false // variable to hold ajax object
/*@cc_on
@if (@_jscript_version >= 5)
try {
pageRequest = new ActiveXObject("Msxml2.XMLHTTP")
}
catch (e){
try {
pageRequest = new ActiveXObject("Microsoft.XMLHTTP")
}
catch (e2){
pageRequest = false
}
}
@end
@*/
if (!pageRequest && typeof XMLHttpRequest != 'undefined')
pageRequest = new XMLHttpRequest()
if (pageRequest){ //if pageRequest is not false
pageRequest.open('GET', url, false); //get page synchronously
pageRequest.send(null);
return( embedpage(pageRequest) );
}
}
function embedpage(request) {
//if viewing page offline or the document was successfully retrieved online (status code=2000)
if (window.location.href.indexOf("http")==-1 || request.status==200)
return(request.responseText);
}
function updateItems() {
category_id = document.getElementById("categoryselect").value;
document.getElementById("itemselect").options[0] = new Option( "Loading...", null, true, true );
document.getElementById("itemselect").disabled = true;
// load new list
newselect = HttpRequest( "itemselect.php?category_id=" + category_id );
document.getElementById("itemselectdiv").innerHTML = newselect;
}
</script>
</head>
<body>
<form>
<select name="category_id" onchange="updateItems();" id="categoryselect">
<option selected="selected"></option>
<?php
$categories = mysql_query( "select id, name from categories order by name" );
while ( $category = mysql_fetch_array( $categories ) ) {
echo '<option value="' . $category["id"] . '">' . $category["name"] . '</option>';
}
?>
</select>
<div id="itemselectdiv">
<select name="item_id" id="itemselect">
<option></option>
</select>
</div>
</form>
</body>
</html>
When the user selects a new category, the client-side Javascript function updateItems() is triggered. This function disables the secondary <select> box and changes its text to "Loading...", so the user can't click on it until the client is done loading the new control.
The function then invokes the AJAX functions to retrieve a page on the server called itemselect.php, passing the selected category ID in the URL; this PHP script returns an HTML <select> control containing the items within the newly selected category. Finally, updateItems() replaces the existing secondary <select> with this new HTML.
As I said, there are other ways, but they all involve reloading the page, which is inefficient and annoying for the user.