0

I'm trying to avoid using AJAX to improve on performance so I only load the lists (sets) of values once for a dropdown field (Child). This Child field will be populated dynamically based on the selection of another dropdown field (Parent).

I want to load the values as a javascript variable that will be assigned to the Child based on the selected value of the Parent.

These values will be written as part of the html (gsp) output.

Any suggestions?

user190117
  • 118
  • 5
Salvador Valencia
  • 1,330
  • 1
  • 17
  • 26

2 Answers2

2

One way to do this is to have GSP write those child values (lists) into JS variables. On parent dropdown's change (onchange), load the appropriate list of values into the children dropdown, based on the parent selection. Modify from this answer

Another way is to have GSP render all the lists data as DOM object (children dropdowns). On parent dropdown's change (onchange), show or hide these DOM objects, based on the parent selection.

Community
  • 1
  • 1
Jayson Cheng
  • 141
  • 4
1

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>&nbsp;</span>                             
            <g:select name="displayCategory" from="${prodCat}" value="${catSelection}" onChange="loadTypes()" optionKey="productCatCode" optionValue="productCatName" noSelection="['':'']" style="width: 150px;"/>                             
            <span>&nbsp;&nbsp;&nbsp;</span>                             
            <label>Product Type</label>                         
            <span>&nbsp;</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: enter image description here

Salvador Valencia
  • 1,330
  • 1
  • 17
  • 26