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:
Steps to create an AEM component that uses a nested multi-field:
- Create a CQ application folder structure.
- Create a template on which the page component is based.
- Create the page component based on the template.
- Create an AEM column component.
- Add a dialog to the component.
- 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.
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:
- To view the CQ welcome page, enter the URL http://[host name]:[port] into a web browser. For example, http://localhost:4502.
- Select CRXDE Lite.
- Right-click the apps folder (or the parent folder), select Create, Create Folder.
- Enter the folder name into the Create Folder dialog box. Enter Nested_Multifield.
- Repeat steps 1-4 for each folder specified in the previous illustration.
- 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.
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:
- To view the CQ welcome page, enter the URL http://[host name]:[port] into a web browser. For example, http://localhost:4502.
- Select CRXDE Lite.
- Right-click /apps/nested_multifield/components/page, then select
Create, Create Component. - 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.
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.
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>
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:
- Select /apps/nested_multifield/components/developer-profile-setup and select Create, Create Dialog.
- In the Title field, enter column.
- Click Ok.
- Delete all nodes under /apps/nested_multifield/components/developer-profile-setup/dialog.
Create the Dialog tab
Follow below steps to create a dialog tab:
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:
8. Select the /apps/nested_multifield/components/developer-profile-setup/dialog/items/items node.
- Name: developer
- Type: cq:Widget
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.
- 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
Add the JS file to the ClientLibs folder after performing below steps:
- Right-click /apps/nested_multifield/components then select New, Node.
- Make sure that the node type is cq:ClientLibraryFolder and name the node clientlibs.
- 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[].
- Create a file named dev-profile.js to the clientlibs node. Add the code shown in this section to the file.
- 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
- Name: cq:listeners
- Type: cq:EditListenersConfig
- 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.
- Go to the CQ Websites page at http://localhost:4502/siteadmin#/content.
- Select New Page.
- Specify the title of the page in the Title field. Enter NestedApp.
- Specify the name of the page in the Name field.
- 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.
- Open the page by clicking the NestedApp page.
- The component will be under the Adobe heading in the sidekick. Drag this component onto the AEM page.
- 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.
Leave a Reply