AEM 6 SP2 - Sample Datasource Touch UI Select Listener

Goal


Add two Granite Select widgets - /libs/granite/ui/components/foundation/form/select with listeners, each listening to the select event of other. In this sample, Country Select widget and Capital Select widget are fed with data sources, countries and capitals respectively for options, selecting country changes capital, vice versa

Demo | Package Install



Solution


1) Login to CRXDE Lite, create folder (nt:folder) /apps/touchui-select-listener

2) Create clientlib (type cq:ClientLibraryFolder/apps/touchui-select-listener/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-select-listener/clientlib/js.txt, add the following

                         listener.js

4) Create file ( type nt:file ) /apps/touchui-select-listener/clientlib/listener.js, add the following code

(function ($, $document) {
    "use strict";

    var COUNTRY = "./country", CAPITAL = "./capital";

    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 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", "18rem");
    }

    $document.on("dialog-ready", function() {
        adjustLayoutHeight();

        //get the country widget
        var country = new CUI.Select({
            element: $("[name='" + COUNTRY +"']").closest(".coral-Select")
        });

        //get the capital widget
        var capital = new CUI.Select({
            element: $("[name='" + CAPITAL +"']").closest(".coral-Select")
        });

        if(_.isEmpty(country) || _.isEmpty(capital)){
            return;
        }

        //workaround to remove the options getting added twice, using CUI.Select()
        country._selectList.children().not("[role='option']").remove();
        capital._selectList.children().not("[role='option']").remove();

        //listener on country select
        country._selectList.on('selected.select', function(event){
            //select country's capital and throw change event for touchui to update ui
            capital._select.val(event.selectedValue).trigger('change');
        });

        //listener on capital select
        capital._selectList.on('selected.select', function(event){
            //select capital's country and throw change event for touchui to update ui
            country._select.val(event.selectedValue).trigger('change');
        });
    });
})($, $(document));


5) Create a simple datasource for countries - /apps/touchui-select-listener/datasource/country/country.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> countries = new LinkedHashMap<String, String>();

    countries.put("INDIA", "India");
    countries.put("USA", "United States");
    countries.put("CHINA", "China");

    final ResourceResolver resolver = resourceResolver;

    DataSource ds = new SimpleDataSource(new TransformIterator(countries.keySet().iterator(), new Transformer() {
        public Object transform(Object o) {
            String country = (String) o;
            ValueMap vm = new ValueMapDecorator(new HashMap<String, Object>());

            vm.put("value", country);
            vm.put("text", countries.get(country));

            return new ValueMapResource(resolver, new ResourceMetadata(), "nt:unstructured", vm);
        }
    }));

    request.setAttribute(DataSource.class.getName(), ds);
%>


6) Create datasource for capitals - /apps/touchui-select-listener/datasource/capital/capital.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> capitals = new LinkedHashMap<String, String>();

    capitals.put("INDIA", "New Delhi");
    capitals.put("USA", "Washington DC");
    capitals.put("CHINA", "Beijing");

    final ResourceResolver resolver = resourceResolver;

    DataSource ds = new SimpleDataSource(new TransformIterator(capitals.keySet().iterator(), new Transformer() {
        public Object transform(Object o) {
            String capital = (String) o;
            ValueMap vm = new ValueMapDecorator(new HashMap<String, Object>());

            vm.put("value", capital);
            vm.put("text", capitals.get(capital));

            return new ValueMapResource(resolver, new ResourceMetadata(), "nt:unstructured", vm);
        }
    }));

    request.setAttribute(DataSource.class.getName(), ds);
%>


7) The Touch UI dialog xml - /apps/touchui-select-listener/sample-select-listener/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="Multifield 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">
                                    <country
                                        jcr:primaryType="nt:unstructured"
                                        sling:resourceType="granite/ui/components/foundation/form/select"
                                        fieldLabel="Country"
                                        name="./country">
                                        <datasource
                                            jcr:primaryType="nt:unstructured"
                                            sling:resourceType="/apps/touchui-select-listener/datasource/country"
                                            addNone="{Boolean}true"/>
                                    </country>
                                    <capital
                                        jcr:primaryType="nt:unstructured"
                                        sling:resourceType="granite/ui/components/foundation/form/select"
                                        disabled="{Boolean}false"
                                        fieldLabel="Capital"
                                        name="./capital">
                                        <datasource
                                            jcr:primaryType="nt:unstructured"
                                            sling:resourceType="/apps/touchui-select-listener/datasource/capital"
                                            addNone="{Boolean}true"/>
                                    </capital>
                                </items>
                            </column>
                        </items>
                    </fieldset>
                </items>
            </column>
        </items>
    </content>
</jcr:root>


8) The component structure in CRXDE Lite





11 comments:

  1. Hi,

    I hope you reply to this.

    You mentioned above--->
    //listener on country select
    country._selectList.on('selected.select', function(event){
    //select country's capital and throw change event for touchui to update ui
    capital._select.val(event.selectedValue).trigger('change');
    });

    I need a similar function for a checkbox, to check if that checkbox is checked or unchecked. If it is checked, I should hide a tab.

    Please help.

    Raja

    ReplyDelete
    Replies
    1. hello raja, is simple jquery call not working? for example to check if the checkbox is checked (assuming there is only one checkbox in dialog) - $(".cq-dialog-content").find(":checkbox").prop("checked") == true

      Delete
  2. I have a json which will have multifield data .Suppose i have 2 records For each record content is rich text in this json when i am reopening the touch ui dialog all the values are getting filled from json except the rich text(content) for each record .Is there any solution?.

    ReplyDelete
    Replies
    1. Hi, can you upload the component/dialog package and share url here for better understanding?

      Delete
    2. https://drive.google.com/file/d/0B3-hSBVuj2wpZkdYelJuY3dvUXc/view?usp=sharing

      Delete
    3. Try this one https://drive.google.com/file/d/0B3-hSBVuj2wpLU5IVTdIYXpiU1U/view?usp=sharing

      Delete
    4. The component doesn't get added in par or rendered, but i think i understand what you are saying.. check this post http://experience-aem.blogspot.com/2015/07/aem-61-touch-ui-composite-multifield-with-rich-text-editor-rte.html

      Delete
  3. Hi,
    is there a way to sort alphabetically the collection ?

    ReplyDelete
  4. ITEM._selectList.on('selected.select', function(event), This event is not being triggered in 6.2 with /libs/granite/ui/components/coral/foundation/form/select. can someone point how we can handle on selection change

    ReplyDelete
    Replies
    1. Did you get a solution for this? If so can you please share? Thanks

      Delete
  5. Hi, Thanks for the great post!!, I am getting the following warning...An instance of Select is already attached to the specified target element. Future versions of CoralUI will throw an exception at this point.

    ReplyDelete