Dynamically update a dropdown list in AEM Touch UI dialog | Community
Skip to main content
Level 2
May 9, 2025
Solved

Dynamically update a dropdown list in AEM Touch UI dialog

  • May 9, 2025
  • 3 replies
  • 767 views

I'm creating a custom AEM component using Touch UI dialogs. I have two dropdown fields: Country and State. I want the State dropdown options to change based on the selected Country. How can I implement this using Granite UI?

Best answer by SantoshSai

Hi @omarkh3,

To implement cascading dropdowns in Touch UI dialogs, you can use the Granite UI datasource approach with JavaScript listeners (using coral-change event) and a servlet to populate the dependent dropdown dynamically.

1. Define your dialog with dynamic state dropdown

Create your cq:dialog structure like below:

<country jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/select" fieldLabel="Country" name="./country" id="countrySelect"> <items jcr:primaryType="nt:unstructured"> <us jcr:primaryType="nt:unstructured" text="USA" value="usa"/> <ca jcr:primaryType="nt:unstructured" text="Canada" value="canada"/> </items> </country> <state jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/select" fieldLabel="State" name="./state" datasource="/bin/getstates" id="stateSelect"/>
 

2. Create a servlet to return state options

Java servlet at /bin/getstates: (Just for your reference)

@SlingServlet(paths = "/bin/getstates", methods = "GET", extensions = "json") public class StateDropdownServlet extends SlingAllMethodsServlet { @Override protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException { String country = request.getParameter("country"); List<JsonObject> states = new ArrayList<>(); if ("usa".equals(country)) { states.add(new JsonObject().put("text", "California").put("value", "ca")); states.add(new JsonObject().put("text", "Texas").put("value", "tx")); } else if ("canada".equals(country)) { states.add(new JsonObject().put("text", "Ontario").put("value", "on")); states.add(new JsonObject().put("text", "Quebec").put("value", "qc")); } response.setContentType("application/json"); response.getWriter().write(states.toString()); } }
 

3. Add a clientlib to handle dropdown change

(function(document, $) { $(document).on("change", "#countrySelect", function() { const selectedCountry = $(this).val(); const stateSelect = $("#stateSelect"); $.getJSON("/bin/getstates?country=" + selectedCountry, function(data) { stateSelect.empty(); $.each(data, function(i, item) { stateSelect.append( $("<coral-select-item>").val(item.value).text(item.text) ); }); }); }); })(document, Granite.$);

Include this in a clientlib (category: cq.authoring.dialog) for your component.

Hope that helps!

3 replies

SantoshSai
Community Advisor
SantoshSaiCommunity AdvisorAccepted solution
Community Advisor
May 9, 2025

Hi @omarkh3,

To implement cascading dropdowns in Touch UI dialogs, you can use the Granite UI datasource approach with JavaScript listeners (using coral-change event) and a servlet to populate the dependent dropdown dynamically.

1. Define your dialog with dynamic state dropdown

Create your cq:dialog structure like below:

<country jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/select" fieldLabel="Country" name="./country" id="countrySelect"> <items jcr:primaryType="nt:unstructured"> <us jcr:primaryType="nt:unstructured" text="USA" value="usa"/> <ca jcr:primaryType="nt:unstructured" text="Canada" value="canada"/> </items> </country> <state jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/select" fieldLabel="State" name="./state" datasource="/bin/getstates" id="stateSelect"/>
 

2. Create a servlet to return state options

Java servlet at /bin/getstates: (Just for your reference)

@SlingServlet(paths = "/bin/getstates", methods = "GET", extensions = "json") public class StateDropdownServlet extends SlingAllMethodsServlet { @Override protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException { String country = request.getParameter("country"); List<JsonObject> states = new ArrayList<>(); if ("usa".equals(country)) { states.add(new JsonObject().put("text", "California").put("value", "ca")); states.add(new JsonObject().put("text", "Texas").put("value", "tx")); } else if ("canada".equals(country)) { states.add(new JsonObject().put("text", "Ontario").put("value", "on")); states.add(new JsonObject().put("text", "Quebec").put("value", "qc")); } response.setContentType("application/json"); response.getWriter().write(states.toString()); } }
 

3. Add a clientlib to handle dropdown change

(function(document, $) { $(document).on("change", "#countrySelect", function() { const selectedCountry = $(this).val(); const stateSelect = $("#stateSelect"); $.getJSON("/bin/getstates?country=" + selectedCountry, function(data) { stateSelect.empty(); $.each(data, function(i, item) { stateSelect.append( $("<coral-select-item>").val(item.value).text(item.text) ); }); }); }); })(document, Granite.$);

Include this in a clientlib (category: cq.authoring.dialog) for your component.

Hope that helps!

Santosh Sai
AmitVishwakarma
Community Advisor
Community Advisor
May 9, 2025

Hi @omarkh3 ,

Try below solution:

1. Touch UI Dialog Setup

In your component’s cq:dialog, define two dropdowns: one static (country), and one dynamic (state):

<country jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/select" fieldLabel="Country" name="./country" id="countrySelect"> <items jcr:primaryType="nt:unstructured"> <us jcr:primaryType="nt:unstructured" text="USA" value="usa"/> <ca jcr:primaryType="nt:unstructured" text="Canada" value="canada"/> </items> </country> <state jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/select" fieldLabel="State" name="./state" id="stateSelect"/>

Keep state dropdown empty for now it will be populated dynamically using JS.

2. Create the Servlet

Create a Sling Servlet that returns states as JSON based on the selected country.

@Component(service = Servlet.class, property = { "sling.servlet.paths=/bin/getstates", "sling.servlet.methods=GET", "sling.servlet.extensions=json" }) public class StateDropdownServlet extends SlingAllMethodsServlet { @Override protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException { String country = request.getParameter("country"); response.setContentType("application/json"); JSONArray states = new JSONArray(); if ("usa".equalsIgnoreCase(country)) { states.put(new JSONObject().put("text", "California").put("value", "ca")); states.put(new JSONObject().put("text", "Texas").put("value", "tx")); } else if ("canada".equalsIgnoreCase(country)) { states.put(new JSONObject().put("text", "Ontario").put("value", "on")); states.put(new JSONObject().put("text", "Quebec").put("value", "qc")); } response.getWriter().write(states.toString()); } }

Don't forget to add this servlet to a core bundle and deploy it.

 

3. JavaScript to Handle the Country Change

In your component's clientlib (category: cq.authoring.dialog), add this JS file, e.g., clientlibs/dialog/js/country-state.js.

(function(document, $) { "use strict"; $(document).on("foundation-contentloaded", function() { var $country = $("#countrySelect"); var $state = $("#stateSelect"); // Listen for country changes $country.on("change", function() { var selectedCountry = $(this).val(); if (!selectedCountry) return; $.ajax({ url: "/bin/getstates?country=" + selectedCountry, dataType: "json", success: function(data) { // Clear existing options $state[0].items.clear(); // Add new options data.forEach(function(item) { $state[0].items.add({ content: { textContent: item.text }, value: item.value }); }); } }); }); }); })(document, Granite.$);

4. Clientlib Configuration

Create a clientlibs/dialog folder with a cq:ClientLibraryFolder node:

categories = ["cq.authoring.dialog"] dependencies = ["granite.jquery"]

And include your country-state.js inside js.txt.

Regards,
Amit

kapil_rajoria
Community Advisor
Community Advisor
May 9, 2025

Hi, please refer:
https://sadyrifat.medium.com/show-hide-aem-cq-dialog-fields-based-on-select-field-selection-a-comprehensive-guide-bee591abd24c

for each value (country) in the dropdown, you can show a different dropdown which will have the list of states associated to that country.

Thanks