Dynamic Dropdowns with Grails Chained Select

Snippet of programming code in IDE
Published on

Building Dynamic Dropdowns with Grails Chained Select

Dropdown menus are a staple feature in modern web applications, allowing users to select one option from a list. However, sometimes you may need to create a more dynamic selection process, where the options in one dropdown menu are dependent on the selection made in another. This is where chained selects come into play. In this tutorial, we'll explore how to implement dynamic dropdowns with Grails chained select plugin, allowing you to build cascading dropdowns with ease.

What are Chained Selects?

Chained selects, also known as cascading or dependent dropdowns, are a set of linked dropdown menus where the options in one dropdown are determined by the selection made in another. This is particularly useful when dealing with hierarchical data or when you want to filter down a large dataset based on user input.

Setting Up the Project

Before we dive into the implementation, make sure you have Grails installed. If not, you can follow the official installation guide here.

Once you have Grails set up, create a new Grails project by running the following command in your terminal:

grails create-app chained-select-demo

This will generate a new Grails application with the name chained-select-demo.

Next, navigate into the newly created project directory:

cd chained-select-demo

Adding the Chained Select Plugin

Grails provides a handy plugin called grails-uisupport which includes the chained select feature. To add this plugin to your project, open the build.gradle file and add the following dependency:

compile "org.grails.plugins:grails-uisupport"

Save the file and run the following command to install the plugin:

grails compile

With the plugin installed, we can now proceed to create the dynamic dropdowns.

Creating Domain Classes

For the purpose of this tutorial, let's assume we are building a simple product management system. We'll need two domain classes – Category and Product. The Product class will have a reference to the Category class, establishing a one-to-many relationship.

// grails-app/domain/demo/Category.groovy

package demo

class Category {
    String name

    static hasMany = [products: Product]
}
// grails-app/domain/demo/Product.groovy

package demo

class Product {
    String name
    String description
    Category category

    static constraints = {
        category nullable: false
    }
}

Configuring Chained Select in the View

Now, let's create a form for adding new products, including the dynamic dropdowns for selecting the category.

// grails-app/views/product/create.gsp

<%@ page contentType="text/html;charset=UTF-8" %>
<html>
  <head>
    <title>Add Product</title>
  </head>
  <body>
    <h1>Add Product</h1>
    <g:form controller="product" action="save">
      <label for="name">Name:</label>
      <g:textField name="name" /><br />
      
      <label for="category">Category:</label>
      <g:select name="category" from="${demo.Category.list()}" optionKey="id" optionValue="name"
                noSelection="['':'-Select Category-']" /><br />
                
      <label for="description">Description:</label>
      <g:textField name="description" /><br />
      
      <g:submitButton name="Save" />
    </g:form>
  </body>
</html>

In the above GSP (Groovy Server Pages) code, we are using the g:select tag to create a dropdown for selecting categories. The from attribute retrieves the list of categories, while optionKey and optionValue specify the properties of the Category class to use for the option values and labels, respectively.

Utilizing Chained Select

With the basic form in place, we'll now integrate the chained select functionality to dynamically update the product form based on the selected category. Modify the GSP to include the chained select script.

// grails-app/views/product/create.gsp

<%@ page contentType="text/html;charset=UTF-8" %>
<html>
  <head>
    <title>Add Product</title>
    <asset:javascript src="chainedselect/chainedselect.js"/>
  </head>
  <body>
    <h1>Add Product</h1>
    <g:form controller="product" action="save" id="productForm">
      <label for="name">Name:</label>
      <g:textField name="name" /><br />
      
      <label for="category">Category:</label>
      <g:select name="category" from="${demo.Category.list()}" optionKey="id" optionValue="name"
                noSelection="['':'-Select Category-']"
                onchange="${remoteFunction(
                    action: 'loadProducts',
                    update: 'productList',
                    params: '\'category=\' + this.value'
                )}" /><br />
      <label for="productList">Select Product:</label>
      <span id="productList">
        <g:select name="product" from="[]" noSelection="['':'-Select Product-']" />
      </span>
      
      <label for="description">Description:</label>
      <g:textField name="description" /><br />
      
      <g:submitButton name="Save" />
    </g:form>
  </body>
</html>

In the modified code, the onchange attribute of the category dropdown triggers the loadProducts action in the ProductController. This action will be responsible for populating the product dropdown based on the selected category.

Implementing Controller Action

Create the loadProducts action in the ProductController to fetch the products based on the selected category.

// grails-app/controllers/demo/ProductController.groovy

package demo

class ProductController {
    def loadProducts = {
        def category = Category.get(params.category as Long)
        def products = category?.products ?: []
        render(template: 'productList', model: [products: products])
    }
}

Here, we retrieve the selected category and fetch its associated products. We then render the product dropdown using the productList template.

Rendering the Product Dropdown

Create a new GSP template called _productList.gsp to render the product dropdown dynamically.

// grails-app/views/product/_productList.gsp

<g:select name="product" from="${products}" optionKey="id" optionValue="name"
          noSelection="['':'-Select Product-']" />

This template simply uses the g:select tag to generate the product dropdown based on the provided list of products.

Testing the Implementation

With everything set up, run your Grails application using the following command:

grails run-app

Navigate to the product creation page, and you should see the category dropdown. Upon selecting a category, the product dropdown should dynamically update based on the selected category. You have successfully implemented chained selects for dynamic dropdowns in Grails!

Closing Remarks

In this tutorial, we explored how to leverage the Grails chained select plugin to create dynamic dropdowns that dynamically fetch data based on user selections. By employing this approach, you can provide a more intuitive and tailored user experience when dealing with linked datasets.

Chained selects are incredibly powerful and can be applied to various scenarios beyond the example provided here. With Grails and the chained select plugin, you have the tools to build sophisticated and responsive user interfaces that cater to complex data relationships.

Now that you've learned how to implement dynamic dropdowns using Grails chained select plugin, experiment with different use cases and take your web applications to the next level with this powerful feature.