Taking the suggestion from Jayson I developed a little test. This is a proof of concept, I think the ultimate goal is to do the second suggestion by hiding and showing the Child when selecting an option on the Parent. That will be left for future refactoring.
So given the following:
Each product Category has a designated list of product Types (just to name our objects).
MODELS:
class ProductCategory {
String productCatCode
String productCatName
String productCatDescr
}
class ProductType {
String productTypeCode
String productTypeName
String productTypeDescr
ProductCategory productCat
}
CONTROLLER:
class PreloadedListsController {
def showCategories() {
def catSelection = params.displayCategory
def typeSelection = params.displayType
def prodCat = ProductCategory.list()
def category1 = ProductCategory.findByProductCatCode("cat1")
def typesListCat1 = category1 ? ProductType.findAllByProductCat(category1) : []
def category2 = ProductCategory.findByProductCatCode("cat2")
def typesListCat2 = category2 ? ProductType.findAllByProductCat(category2) : []
[prodCat: prodCat, typesListCat1: typesListCat1, typesListCat2: typesListCat2, catSelection: catSelection]
}
}
VIEW:
<head>
<title>Dynamically Loaded Dropdowns</title>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
<meta name="layout" content="main">
<script type="text/javascript">
function clearDropdown(selectList) {
var length=selectList.options.length;
for (count=selectList.options.length-1; count>=0; count--) {
selectList.remove(count);
}
}
function loadTypes() {
var catList=document.getElementById("displayCategory");
var typeList=document.getElementById("displayType");
var catSel= catList.options[catList.selectedIndex].value;
//Clear Child dropdown before we load new values
clearDropdown(typeList);
if (catSel) {
if(catSel == "cat1") {
// Create empty option
clearDropdown(typeList);
var optionItem=document.createElement("option");
optionItem.text=" ";
typeList.add(optionItem);
// Create all options from query
<g:each in="${typesListCat1}" var="item">
var optionItem=document.createElement("option");
${raw("optionItem.text=\"${item}\"; ") }
typeList.add(optionItem);
</g:each>
} else if (catSel == "cat2") {
// Create empty option
clearDropdown(typeList);
var optionItem=document.createElement("option");
optionItem.text=" ";
typeList.add(optionItem);
// Create all options from query
<g:each in="${typesListCat2}" var="item">
var optionItem=document.createElement("option");
${raw("optionItem.text=\"${item}\"; ") }
typeList.add(optionItem);
</g:each>
}
}
}
</script>
</head>
<body>
<g:form action="showCategories" controller="PreloadedLists" name="searchForm">
<div>
<label>Product Category</label>
<span> </span>
<g:select name="displayCategory" from="${prodCat}" value="${catSelection}" onChange="loadTypes()" optionKey="productCatCode" optionValue="productCatName" noSelection="['':'']" style="width: 150px;"/>
<span> </span>
<label>Product Type</label>
<span> </span>
<select name="displayType" id="displayType"></select>
</div>
<div>
<g:submitButton name="search" value="Search" />
</div>
</g:form>
</body>
BOOTSTRAP:
def prodCat01 = new ProductCategory(productCatCode: "cat1", productCatName: "prodCategory1", productCatDescr: "Product Category #1").save(failOnError: true)
def prodType01 = new ProductType(productTypeCode: "prod1", productTypeName: "Product One", productCat: prodCat01, productTypeDescr: "This is Product One Description.").save(failOnError: true)
def prodType02 = new ProductType(productTypeCode: "prod2", productTypeName: "Product Two", productCat: prodCat01, productTypeDescr: "This is the Second Product Description.").save(failOnError: true)
def prodType03 = new ProductType(productTypeCode: "prod3", productTypeName: "Product Three", productCat: prodCat01, productTypeDescr: "This is the THIRD Product Description. The best product of all. Also number three is a lucky number!").save(failOnError: true)
def prodType04 = new ProductType(productTypeCode: "prod4", productTypeName: "Product FOUR", productCat: prodCat01, productTypeDescr: "FOURTH product in the list. The most popular product is product number FOUR!!").save(failOnError: true)
def prodCat02 = new ProductCategory(productCatCode: "cat2", productCatName: "prodCategory2", productCatDescr: "Product Category #2").save(failOnError: true)
def prodType05 = new ProductType(productTypeCode: "prod5", productTypeName: "Product FIVE", productCat: prodCat02, productTypeDescr: "This is Product Description #5.").save(failOnError: true)
def prodType06 = new ProductType(productTypeCode: "prod6", productTypeName: "Product Six", productCat: prodCat02, productTypeDescr: "This is the Sixth Product Description.").save(failOnError: true)
RESULTS:
It worked. Notice how I preload the possible Child lists available for each Parent option. I needed to use the Raw function in order to make the <g:each>
loop to work in the gsp. Additional work is needed to handle the selected values in the params
object since the form submits to the same action (already read in the catSelection
and typeSelection
variables).
SCREEN OUTPUT:
