AEM: Create a Nested Multi-Field CQ Dialog Widget

Nested multi-field cq dialog widget  or custom Adobe Experience Manager (AEM) component is one that uses a nested multi-field control located in a dialog. A nested multi-field control is an inner multi-field control within an outer multi-field control and lets an author dynamically enter data.

For example, assume the AEM control lists developers and each developer has an unknown number of skills to display. That is, within the inner multi-field, the author enter details such as professional skill set. The outer multi-field determines how may developers to display.

Lets create Nested multi-field cq dialog widget as shown below:

adobe-cq-create-nested-multi-field-component-aemcq5tutorials

Steps to create an AEM component that uses a nested multi-field:

  1.  Create a CQ application folder structure.
  2. Create a template on which the page component is based.
  3. Create the page component based on the template.
  4. Create an AEM  column component.
  5. Add a dialog to the component.
  6. Create a CQ web page that uses the new component.
Creating CQ application folder structure 

Lets create an Adobe CQ application folder structure which contains templates, components, and pages by using CRXDE Lite.

adobe-CQ-project-structure-AppSetup-simplycracked
CQ Application Folder Structure

 

The following describes each application folder:

  • application name: contains all of the resources that an application uses. The resources can be templates, pages, components, and so on.
  • components: contains components that your application uses.
  • page: contains page components. A page component is a script such as a JSP file.
  • global: contains global components that your application uses.
  • template: contains templates on which you base page components.
  • src: contains source code that comprises an OSGi component (this development article does not create an OSGi bundle using this folder).
  • install: contains a compiled OSGi bundles container.

For creating an application folder structure, follow below steps:

  1. To view the CQ welcome page, enter the URL http://[host name]:[port] into a web browser. For example, http://localhost:4502.
  2. Select CRXDE Lite.
  3. Right-click the apps folder (or the parent folder), select Create, Create Folder.
  4. Enter the folder name into the Create Folder dialog box. Enter Nested_Multifield.adobe-cq-create-netsed-multifield-component-simplycracked-0
  5. Repeat steps 1-4 for each folder specified in the previous illustration.
  6. Click the Save All button.

Note: Never forget to click on SaveAll while working on CRXDE.

Creating a Template

Lets create a template by using CRXDE Lite. A CQ template enables you to define a consistent style for the pages in your application. A template comprises of nodes that specify the page structure.

For creating a template, follow below steps:

1. To view the CQ welcome page, enter the URL http://[host name]:[port] into a web browser. For example, http://localhost:4502.
2. Select CRXDE Lite.
3. Right-click the template folder (within your application), select Create, Create
Template.
4. Enter the following information into the Create Template dialog box:

  • Label: The name of the template to create. Enter multifieldTemplate.
  • Title: The title that is assigned to the template.
  • Description: The description that is assigned to the template.
  • Resource Type: The component’s path that is assigned to the template and copied to implementing pages. Enter /apps/nested_multifield/components/page/multifieldTemplate.
  • Ranking: The order (ascending) in which this template will appear in relation to other templates. Setting this value to 1 ensures that the template appears first in the list.
adobe-cq-create-nested-multifield-component-simplycracked-1
Create Template using crxde

5. Add a path to Allowed Paths. Click on the plus sign and enter the following value: /content(/.*)?.
6. Click Next for Allowed Parents.
7. Select OK on Allowed Children.

Learn how to Create a Template in CQ
Creating a render component that uses the template

By default, a component has at least one default script, identical to the name of the component. To create a render component, perform these tasks:

  1. To view the CQ welcome page, enter the URL http://[host name]:[port] into a web browser. For example, http://localhost:4502.
  2. Select CRXDE Lite.
  3. Right-click /apps/nested_multifield/components/page, then select
    Create, Create Component.
  4. Enter the following information into the Create Component dialog box:
  • Label: The name of the component to create. Enter multifieldTemplate.
  • Title: The title that is assigned to the component.
  • Description: The description that is assigned to the template.
  • Super Type:foundation/components/page.
adobe-cq-create-nested-multifield-component-simplycracked-2
Creating a Page Component in AEM

5.  Select Next for Advanced Component Settings and Allowed Parents.

6.  Select OK on Allowed Children.

7. Open the templateMultifield.jsp located at: /apps/nested_multifield/components/page/multifieldTemplate/multifieldTemplate.jsp.

adobe-cq-create-nested-multifield-component-simplycracked-3

8. Enter the following JSP code.

 <html>
<%@include file="/libs/foundation/global.jsp" %>
<cq:include script="/libs/wcm/core/components/init/init.jsp"/>
<body>

<h1>Here is where your custom AEM component will go</h1>

<cq:include path="par" resourceType="foundation/components/parsys" />
</body>
</html>

adobe-cq-create-nested-multifield-component-simplycracked-4

Learn how to create a component in CQ
Creating AEM custom component that uses a nested multifield

After you setup the AEM folder structure, create the AEM custom multi-field component by performing below steps:

1. Right click on /apps/nested_multifield/components and then select New, Component.

2. Enter the following information into the Create Component dialog box:

  • Label: The name of the component to create. Enter developer-profile-setup.
  • Title: The title that is assigned to the component. Enter developer-profile-setup.
  • Description: The description that is assigned to the template. Enter developer-profile-setup.
  • Super Resource Type: Enter foundation/components/parbase.
  • Group: The group in the side rail or side kick where the component appears. Enter Adobe. (The developers component is located under the Adobe heading in the Touch UI side rail. Also appears in Adobe in the classic view sidekick.)
  • Allowed parents: Enter */*parsys.

3. Click Ok.

 Add a dialog to Custom Nested Multi-Field AEM component  
A dialog lets an author click on the component in the Touch UI (or Classic UI) view.

To create the dialog, perform these tasks:

  1.  Select /apps/nested_multifield/components/developer-profile-setup and select Create, Create Dialog.
  2.  In the Title field, enter column.
  3.  Click Ok.
  4.  Delete all nodes under /apps/nested_multifield/components/developer-profile-setup/dialog.
Create the Dialog tab

Follow below steps to create a dialog tab:

1. Click on the following node: /apps/nested_multifield/components/developer-profile-setup/dialog.
2. Right click and select Create, Create Node
3. Enter the following values:
  • Name: items
  • Type: cq:Widgetadobe-cq-create-nested-multifield-component-simplycracked-5
4. Add the following property:
  • xtype (String) – tabpanel
    adobe-cq-create-nested-multifield-component-simplycracked-6

5. Select the /apps/nested_multifield/components/developer-profile-setup/dialog/items node.

6. Right click and select Create, Create Node.

7. Enter the following values:

  • Name: items
  • Type: cq:WidgetCollectionadobe-cq-create-nested-multifield-component-simplycracked-7

8. Select the /apps/nested_multifield/components/developer-profile-setup/dialog/items/items node.

9. Right click and select Create, Create Node.
10. Enter the following values:
  • Name: developer
  • Type: cq:Widget
11. Add the following properties:
  • title (String) -Developer (title that appears on the tab)
  • xtype (String) – panel (defines the data type of this field.)adobe-cq-create-nested-multifield-component-simplycracked-8
12. Click on the following node:/apps/nested_multifield/components/developer-profile-setup/dialog/items/items/developer.
13. Right click and select Create, Create Node.

14. Enter the following values:

  • Name: items
  • Type: cq:WidgetCollection

15. Select the Select the /apps/nested_multifield/components/developer-profile-setup/dialog/items/items/developer/items.

16. Right click and select Create, Create Node.
17. Enter the following values:
  • Name: developernode
  • Type: cq:Widget

18. Add the following properties:

  • fieldLabel (String) – Developer’s Data
  • name (String) – ./devdata
  • xtype (String) – multifield

19 . Select the /apps/nested_multifield/components/developer-profile-setup/dialog/items/items/developer/items/developernode.

20. Right click and select Create, Create Node.

21. Enter the following values:

  • Name: fieldConfig
  • Type: cq:Widget

22. Add the following properties:

  • xtype (String) – devprofile

adobe-cq-create-nested-multifield-component-simplycracked-9

Add the JS file to the ClientLibs folder after performing below steps:
  1. Right-click /apps/nested_multifield/components then select New, Node.
  2. Make sure that the node type is cq:ClientLibraryFolder and name the node clientlibs.
  3. Right click on clientlibs and select Properties. Add the categories property to this node. Specify simplycracked.custom.widget.devprofile and ensure the type is String[].
  4. Create a file named dev-profile.js to the clientlibs node. Add the code shown in this section to the file.
  5. Add a TXT file to the clientlibs node named js.txt. Add dev-profile.js to this txt file.

 Adding JavaScript file defines a custom xtype to a cq:ClientLibraryFolder node

 dev-profile.js file


try {
    if (typeof SimplyCracked == 'undefined') {
        SimplyCracked = {}; // creating namespace
    }
    SimplyCracked.SitemapDatacollection = CQ.Ext.extend(CQ.form.CompositeField, {
        /**
         * @private
         * @type CQ.Ext.form.TextField
         */
        hiddenField: null,
        /**
         * @private
         * @type CQ.Ext.form.PathField
         */
        developerName: null,
        /**
         * @private
         * @type CQ.Ext.form.PathField
         */
        developerDesc: null,
        /**
         * @private
         * @type CQ.Ext.form.MultiField
         */
        replaceMulti: null,
        /**
         * @private
         * @type CQ.Ext.form.CheckBox
         */
        lastMod: null,
        /**
         * @private
         * @type CQ.Ext.form.ComboBox
         */
        changeFreq: null,
        /**
         * @private
         * @type CQ.Ext.form.ComboBox
         */
        priority: null,
        /**
         * @private
         * @type CQ.Ext.form.MultiField
         */
        skillSet: null,
        /**
         * @private
         * @type CQ.Ext.form.CheckBox
         */
        temporaryDisable: null,
        constructor: function(config) {
            config = config || {};
            var defaults = {
                "border": true,
                "padding": 10,
                "style": "padding:10px 0 0 5px;",
                "layout": "form",
                "labelWidth": 200
            };
            config = CQ.Util.applyDefaults(config, defaults);
            SimplyCracked.SitemapDatacollection.superclass.constructor
                .call(this, config);
        },
        // overriding CQ.Ext.Component#initComponent
        initComponent: function() {
            SimplyCracked.SitemapDatacollection.superclass.initComponent
                .call(this);
            // Hidden field
            this.hiddenField = new CQ.Ext.form.Hidden({
                name: this.name
            });
            this.add(this.hiddenField);
            this.developerName = new CQ.Ext.form.TextField({
                fieldLabel: "Developer's Name",
                allowBlank: false,
                width: 400,
                listeners: {
                    change: {
                        scope: this,
                        fn: this.updateHidden
                    },
                    dialogclose: {
                        scope: this,
                        fn: this.updateHidden
                    }
                }
            });
            this.add(this.developerName);
            this.developerDesc = new CQ.Ext.form.TextArea({
                fieldLabel: "About Developer",
                fieldDescription: "Provide a detail description about developer",
                allowBlank: false,
                width: 400,
                listeners: {
                    change: {
                        scope: this,
                        fn: this.updateHidden
                    },
                    dialogclose: {
                        scope: this,
                        fn: this.updateHidden
                    },
                }
            });
            this.add(this.developerDesc);
            //define the inner multifield
            this.skillSet = new CQ.form.MultiField({
                fieldLabel: "Add Skills",
                fieldDescription: "Click '+' to add your Skills",
                width: 400,
                fieldConfig: {
                    "xtype": "textfield",
                    allowBlank: false,
                },
                listeners: {
                    change: {
                        scope: this,
                        fn: this.updateHidden
                    }
                }
            });
            this.add(this.skillSet);
        },
        // overriding CQ.form.CompositeField#setValue
        setValue: function(value) {
            var readVal = '';
            var storeVal = '';
            var skillSetValues = '';
            if (value) {
                var colValue = value.split('|');
                if (colValue.length > 0) {
                    readVal = colValue[0];
                    storeVal = colValue[1];
                    skillSetValues = colValue[2];
                }
            }
            this.developerName.setValue(readVal);
            this.developerDesc.setValue(storeVal);
            this.skillSet.setValue(skillSetValues.split(','));
        },
        // overriding CQ.form.CompositeField#getValue
        getValue: function() {
            return this.getRawValue();
        },
        getRawValue: function() {
            //var temporaryDisableVal = this.temporaryDisable.getValue() || "";
            var readVal = this.developerName.getValue() || "";
            var storeVal = this.developerDesc.getValue() || "";
            //var replaceMultiValues  = this.replaceMulti.getValue() || "";
            // var lastModVal          = this.lastMod.getValue() || "";
            //var changeFreqVal       = this.changeFreq.getValue() || "";
            //var priorityVal         = this.priority.getValue() || "";
            var skillSetValues = this.skillSet.getValue() || "";
            // if (temporaryDisableVal == '')
            //     temporaryDisableVal = " ";
            var value = readVal + "|" + storeVal + "|" +
                skillSetValues;
            this.hiddenField.setValue(value);
            return value;
        },
        updateHidden: function() {
            this.hiddenField.setValue(this.getValue());
        },
        destroyRichText: function() {
            this.el.dom = {};
        }
    });
    CQ.Ext.reg('devprofile', SimplyCracked.SitemapDatacollection);
} catch (e) {
    // suppressing error.
    // error occurs for CQ.form.CompositeField in mobile devices.
}

 

Update developer-profile-setup JSP file

The developer-profile-setup.jsp is the main JSP file for the component and is located at:

/apps/nested_multifield/components/developer-profile-setup/developer-profile-setup.jsp

<jsp:directive.include file="/libs/foundation/global.jsp" />
<cq:includeClientLib categories="simplycracked.custom.widget.devprofile" />
 AEM Custom Nested Multifieid Component
<%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0" %>
 <%@taglib prefix="cq" uri="http://www.day.com/taglibs/cq/1.0" %>
 <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

 <%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

<div id="wrapper" style="height:auto;border:1px solid grey">
 Developer's Data
 <c:forEach var="items" items="${properties.devdata}" varStatus="status">
 <c:set var="listItem" value="${fn:split(items,'|')}" />
 <c:set var="developerName" value="${fn:trim(listItem[0])}" />
 <c:set var="about" value="${fn:trim(listItem[1])}" />
 <c:set var="skills" value="${fn:trim(listItem[2])}" />


<div class="dev-profile" style="background-color:#E0F8F7;height:auto;border:1px solid grey;margin-top:15px">
 Name : ${developerName} About : ${about} Skills : ${skills}
 </div>

</c:forEach>
 </div>

Creating EditConfig node

Perform below steps to define behavior of our nested multi-filed cq dialog widget or AEM Component:-

Perform the following tasks:

1. Select /apps/nested_multifield/components/developer-profile-setup.

2. Right click and select Create, Create Node

3. Enter the following values:

  • Name: cq:editConfig
  • Type: cq:EditConfig

4. Add the following property:

  • cq:actions (String[]) – EDITANNOTATECOPYMOVEDELETEINSERT
  • cq:dialogMode (String) – floating
5. Select /apps/nested_multifield/components/developer-profile-setup/cq:editConfig.
6. Right click and select Create, Create Node.
7. Enter the following values:
  • Name: cq:listeners
  • Type: cq:EditListenersConfig
8. Add the following property:
  • afteredit (String) – REFRESH_PAGE
Create a CQ web page that uses the nested multi-field component

Follow below steps to create an AEM page that displays the component.

  1. Go to the CQ Websites page at http://localhost:4502/siteadmin#/content.
  2. Select New Page.
  3. Specify the title of the page in the Title field. Enter NestedApp.
  4. Specify the name of the page in the Name field.
  5. Select multifieldTemplate from the template list that appears. This value represents the template that is created in this development article. If you do not see it, then repeat the steps in this development article. For example, if you made a typing mistake when entering in path information, the template will not show up in the New Page dialog box.
  6. Open the page by clicking the NestedApp page.
  7. The component will be under the Adobe heading in the sidekick. Drag this component onto the AEM page.
  8. Open the dialog and enter values into the dialog fields.

Note: If the CQ sidekick is empty, you can populate it by clicking the Design button located at the bottom of the sidekick.

Spread the love

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.