Goal
Add two Granite Select widgets - /libs/granite/ui/components/foundation/form/select with second select being dynamic. In this example, selecting language fills the country select widget with available countries for that language in CRX /libs/wcm/core/resources/languages
Demo | Package Install
Solution
1) Login to CRXDE Lite, create folder (nt:folder) /apps/touchui-fill-second-select
2) Create clientlib (type cq:ClientLibraryFolder) /apps/touchui-fill-second-select/clientlib, set a property categories of String type to cq.authoring.dialog and dependencies of type String[] to underscore
3) Create file ( type nt:file ) /apps/touchui-fill-second-select/clientlib/js.txt, add the following
listener.js
4) Create file ( type nt:file ) /apps/touchui-fill-second-select/clientlib/listener.js, add the following code
(function ($, $document) { "use strict"; var LANGUAGE = "./language", COUNTRY = "./country"; function adjustLayoutHeight(){ //with only two selects, the second select drop down is not visible when expanded, so adjust the layout height //fixedcolumns i guess doesn't support css property height, so fallback to jquery //http://docs.adobe.com/docs/en/aem/6-0/develop/ref/granite-ui/api/jcr_root/libs/granite/ui/components/foundation/layouts/fixedcolumns/index.html $(".coral-FixedColumn-column").css("height", "20rem"); } $document.on("dialog-ready", function() { adjustLayoutHeight(); //http://docs.adobe.com/docs/en/aem/6-0/develop/ref/granite-ui/api/jcr_root/libs/granite/ui/components/foundation/form/select/index.html var language = new CUI.Select({ element: $("[name='" + LANGUAGE +"']").closest(".coral-Select") }); var country = new CUI.Select({ element: $("[name='" + COUNTRY +"']").closest(".coral-Select") }); if(_.isEmpty(country) || _.isEmpty(language)){ return; } var langCountries = {}; //workaround to remove the options getting added twice, using CUI.Select() language._selectList.children().not("[role='option']").remove(); function fillCountries(selectedLang, selectedCountry){ country._select.children().remove(); country._selectList.children().remove(); _.each(langCountries, function(value, lang){ if( (lang.indexOf(selectedLang) !== 0) || (value.country == "*") ){ return; } $("<option>").appendTo(country._select) .val(lang).html(value.country); }); country = new CUI.Select({ element: $("[name='" + COUNTRY +"']").closest(".coral-Select") }); if(!_.isEmpty(selectedCountry)){ country._select.val(selectedCountry).trigger('change'); } } //listener on language select for dynamically filling the countries on language select language._selectList.on('selected.select', function(event){ fillCountries(event.selectedValue); }); //get the langs list $.getJSON("/libs/wcm/core/resources/languages.2.json").done(function(data){ langCountries = data; var $form = country.$element.closest("form"); //get the second select box (country) saved value $.getJSON($form.attr("action") + ".json").done(function(data){ if(_.isEmpty(data)){ return; } fillCountries(language.getValue(), data.country); }) }); }); })($, $(document));
5) Create a simple datasource for languages - /apps/touchui-fill-second-select/datasource/language/language.jsp
<%@include file="/libs/granite/ui/global.jsp"%> <%@ page import="com.adobe.granite.ui.components.ds.DataSource" %> <%@ page import="com.adobe.granite.ui.components.ds.ValueMapResource" %> <%@ page import="java.util.HashMap" %> <%@ page import="org.apache.sling.api.wrappers.ValueMapDecorator" %> <%@ page import="com.adobe.granite.ui.components.ds.SimpleDataSource" %> <%@ page import="org.apache.commons.collections.iterators.TransformIterator" %> <%@ page import="java.util.Map" %> <%@ page import="java.util.LinkedHashMap" %> <%@ page import="org.apache.commons.collections.Transformer" %> <%@ page import="org.apache.sling.api.resource.*" %> <% final Map<String, String> languages = new LinkedHashMap<String, String>(); languages.put("ar", "Arabic"); languages.put("en", "English"); languages.put("de", "German"); final ResourceResolver resolver = resourceResolver; DataSource ds = new SimpleDataSource(new TransformIterator(languages.keySet().iterator(), new Transformer() { public Object transform(Object o) { String language = (String) o; ValueMap vm = new ValueMapDecorator(new HashMap<String, Object>()); vm.put("value", language); vm.put("text", languages.get(language)); return new ValueMapResource(resolver, new ResourceMetadata(), "nt:unstructured", vm); } })); request.setAttribute(DataSource.class.getName(), ds); %>
7) The Touch UI dialog xml - /apps/touchui-fill-second-select/fill-second-select/cq:dialog
<?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" jcr:primaryType="nt:unstructured" jcr:title="Select TouchUI Component" sling:resourceType="cq/gui/components/authoring/dialog" helpPath="en/cq/current/wcm/default_components.html#Text"> <content jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/container"> <layout jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/> <items jcr:primaryType="nt:unstructured"> <column jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/container"> <items jcr:primaryType="nt:unstructured"> <fieldset jcr:primaryType="nt:unstructured" jcr:title="Sample Select" sling:resourceType="granite/ui/components/foundation/form/fieldset"> <layout jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/> <items jcr:primaryType="nt:unstructured"> <column jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/container"> <items jcr:primaryType="nt:unstructured"> <language jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/form/select" fieldLabel="Language" name="./language"> <datasource jcr:primaryType="nt:unstructured" sling:resourceType="/apps/touchui-fill-second-select/datasource/language" addNone="{Boolean}true"/> </language> <country jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/form/select" fieldLabel="Country" name="./country"/> </items> </column> </items> </fieldset> </items> </column> </items> </content> </jcr:root>
Not able to see the dropdown .....
ReplyDeleteable to see the dropdown. But selection change is throwing on country._select. And we are planning to populate second dropdown base on the first dropdown selection. Can you please look into this.
ReplyDeleteI literally copied these files and created a component. I get the same issue. May be this too does not work in AEM 6.2??
DeleteĐơn vị chuyên nhận order đặt mua hàng phụ kiện thời trang
ReplyDeleteCông ty chuyên nhận order đặt mua hàng thời trang ở Quảng Châu
Công ty chuyên nhận order đặt mua hàng quần áo ở Quảng Châu
Hi Sreenkath,
ReplyDeleteI have a multiselect dropdown in my dialog and I am getting the selected values as node properties within /content dir. Can i have the selected values as seperate nodes instead?
Please make this change in the listener.js at line 59 and this will work fine:
ReplyDelete//listener on language select for dynamically filling the countries on language select
language._selectList.on('selected.select', function(event){
fillCountries(event.selected);
});
Thanks, you saved my life. I wish you were my teammate.
Delete