Create Touch UI Nested MultiField Dialog in AEM

In this tutorial we will see how to create Touch UI Nested Multifield component using HTL in aem. This tutorial is in continuation with our last tutorial about creating multifiled component in aem. In this tutorials also we will be using ACS common (Adobe consulting services) multifield component that allows developers to create a nested multifield (multifield inside multifield) of a fieldset (group of different fields) .

Sometimes developer get into a situation where they need to use a nested multifield dialog to meet customer requirement. AEM developers require huge effort till aem 6.2 to create a nested multifiled as it has many issue, but with release of aem 6.3 and stable service pack 1. It is now a matter of couple of minutes to create a nested multifiled.

After completing this tutorial, you will have a clear understanding about:-

Create Nested Touch UI MultiField Component in AEM 6.3 using HTL:-


Lets extend use case of creating a user menu for your website and retrieving its value stored in the form of JSON Array from crxde/JCR repository that we have used in our previous tutorial. Follow below steps to create acs commons nested multi field component :-

nested-touchui-multifield-aem

  • Login to crxde.
  • Go to /apps/<project-name>/<path-to-component> [For Ex:- /apps/my-aem-project/components/content/ ]
  • Create a new component under content node [For Ex:- In our example nested-userSubMenu]
  • Paste below content.xml of our multi field component.

nested-userSubMenu

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:description="Nested Multi Field Example"
jcr:primaryType="cq:Component"
jcr:title="Nested Multi Field"
componentGroup="aemcq5tutorials"/>

cq:dialog content.xml:-

<?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="User Menu"
sling:resourceType="cq/gui/components/authoring/dialog">
<content
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/container">
<layout
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/layouts/tabs"
type="nav"/>
<items jcr:primaryType="nt:unstructured">
<tabs
jcr:primaryType="nt:unstructured"
jcr:title="General"
sling:resourceType="granite/ui/components/foundation/container">
<items jcr:primaryType="nt:unstructured">
<usersubmenu
jcr:primaryType="nt:unstructured"
jcr:title="User Submenu"
sling:resourceType="granite/ui/components/foundation/section">
<layout
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/>
<items jcr:primaryType="nt:unstructured">
<tab
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/container">
<items jcr:primaryType="nt:unstructured">
<usersubmenudetails
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/multifield"
class="full-width"
fieldDescription="Click 'Add field' to add a new User Submenu title and links"
fieldLabel="User Submenu Items">
<field
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/fieldset"
acs-commons-nested=""
name="./myUserSubmenu">
<layout
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"
method="absolute"/>
<items jcr:primaryType="nt:unstructured">
<column
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/container">
<items jcr:primaryType="nt:unstructured">
<title
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/textfield"
fieldDescription="Enter User Submenu title"
fieldLabel="User Submenu Title"
name="./title"/>
<link
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/pathbrowser"
fieldDescription="Enter User Submenu Link"
fieldLabel="User Submenu Link"
name="./link"
rootPath="/content"/>
<usernestedsubmenudetails
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/multifield"
class="full-width"
fieldDescription="Click 'Add field' to add a new User Submenu title and links"
fieldLabel="User Nested Submenu Items">
<field
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/fieldset"
acs-commons-nested=""
name="./myNestedUserSubmenu">
<layout
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"
method="absolute"/>
<items jcr:primaryType="nt:unstructured">
<column
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/container">
<items jcr:primaryType="nt:unstructured">
<title
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/textfield"
fieldDescription="Enter User Nested Submenu title"
fieldLabel="User Nested Submenu Title"
name="./subtitle"/>
</items>
</column>
</items>
</field>
</usernestedsubmenudetails>
</items>
</column>
</items>
</field>
</usersubmenudetails>
</items>
</tab>
</items>
</usersubmenu>
</items>
</tabs>
</items>
</content>
</jcr:root>

Note:- To use acs commons multifield it is mandatory to add acs-commons-nested=”” property to a fieldset within a multifield node  like at myUserSubmenu node in our example. acs-commons-nested=”” acs-commons-nested=”JSON_STORE” or means we want to store multifiled data as JSON Array. To store multi filed data as seperate child node use  acs-commons-nested=”NODE_STORE”.

cq:editConfig content.xml:-

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="cq:EditConfig">
<cq:listeners
jcr:primaryType="cq:EditListenersConfig"
afteredit="REFRESH_SELF"/>
</jcr:root>

dialog.xml

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="cq:Dialog"
xtype="dialog"/>

Note:- dialog.xml or editConfig.xml is required because if we don’t have dialog in our component then it wont get displayed in side rail of Touch UI. 

  • After adding these nodes content.xml. Open component rending script or html file [For EX:- nested-userSubMenu.html] and add below code to it.
Click here to configure Nested Multi Field User Menu
<div data-sly-use.multiItems="aemlearning.pojo.TouchNestedMultiFieldComponentUse">
<div data-sly-list.head="${multiItems.multiFieldItems}">
<p><b>Page Name:</b> ${head.title}</p>
<p><b>Page Path:</b> ${head.link}</p>
<p><b>Nested Sub Title:</b> ${head.subtitle}</p>
</div>
</div> 

Now our component structure should look like below screenshot:-

nested-multifield-jcr-structure

Note:- The only important thing that you have to consider is to use acs-common-nested property on nested multifield node also. 

Retrieve values from Nested Multifield dialog:-

Now lets see how to retrieve values stored in jcr for nested multifield component.

Lets create two java file TouchNestedMultiFieldBean and TouchNestedMultiFieldComponentUse to retrieve values from crxde.

TouchNestedMultiFieldBean.java

package aemlearning.bean;

/**
 * POJO for Nested Multi Field items
 * 
 * @author aahlawat
 *
 */
public class TouchNestedMultiFieldBean {

private String title;
 private String link;
 private String subtitle;

public String getTitle() {
 return title;
 }

public void setTitle(String title) {
 this.title = title;
 }

public String getLink() {
 return link;
 }

public void setLink(String link) {
 this.link = link;
 }

public String getSubtitle() {
 return subtitle;
 }

public void setSubtitle(String subtitle) {
 this.subtitle = subtitle;
 }
}

TouchNestedMultiFieldComponentUse.java

package aemlearning.pojo;

import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.adobe.cq.sightly.WCMUsePojo;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

import aemlearning.bean.TouchNestedMultiFieldBean;

public class TouchNestedMultiFieldComponentUse extends WCMUsePojo {

private static final Logger LOGGER = LoggerFactory.getLogger(TouchNestedMultiFieldComponentUse.class);
private List<TouchNestedMultiFieldBean> submenuItems = new ArrayList<>();

@Override
public void activate() throws Exception {
setNestedMultiFieldItems();
}

/**
* Method to get Multi field data
*
* @return submenuItems
*/
private List<TouchNestedMultiFieldBean> setNestedMultiFieldItems() {

JsonObject jObj;
JsonArray jNestedArr;
Gson gson = new Gson();
try {
String[] itemsProps = getProperties().get("myUserSubmenu", String[].class);
if (itemsProps != null) {
for (int i = 0; i < itemsProps.length; i++) {
JsonElement json = gson.fromJson(itemsProps[i], JsonElement.class);
jObj = json.getAsJsonObject();
TouchNestedMultiFieldBean menuItem = new TouchNestedMultiFieldBean();
String title = jObj.get("title").toString();
String path = jObj.get("link").toString();
jNestedArr = jObj.getAsJsonArray("myNestedUserSubmenu");
if (!jNestedArr.isJsonNull() && jNestedArr.size() > 0) {
JsonObject jNestedObj = jNestedArr.get(0).getAsJsonObject();
menuItem.setSubtitle(jNestedObj.get("subtitle").toString());
}
menuItem.setTitle(title);
menuItem.setLink(path);
submenuItems.add(menuItem);
}
}
} catch (Exception e) {
LOGGER.error("Exception while Multifield data {}", e.getMessage(), e);
}
return submenuItems;
}

public List<TouchNestedMultiFieldBean> getMultiFieldItems() {
return submenuItems;
}
}

That’s it you are done

  • Just build the component from eclipse.
  • Drag and drop usermenu component on any parsys.
  • Enter the values and save it.

Value stored in CRX/JCR in form of JSON Array:-

json-aem-multifield

You can download the code used in above tutorial for creating touch ui nested multifield dialog from my repository https://bitbucket.org/aahlawa/aem-learning/branch/nested-multifield

Spread the love
  • 32
  •  
  •  
  •  
  •  
  •  

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.