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?
Solved! Go to Solution.
Views
Replies
Total Likes
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.
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"/>
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());
}
}
(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!
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.
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"/>
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());
}
}
(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!
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
Hi, please refer:
https://sadyrifat.medium.com/show-hide-aem-cq-dialog-fields-based-on-select-field-selection-a-compre...
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
Views
Likes
Replies
Views
Likes
Replies
Views
Likes
Replies