How to customize the page properties Dialog to include dynamic DropDownList in AEM/CQ5
This post will explain the details to customize page properties Dialog in both Touch and Classic UI's, the version used for implementing this is Adobe Experience Manager(AEM) 6.1.The basic page properties dialog will be displayed if the sling:resourceSuperType of the page rendering component is specified as foundation page component(wcm/foundation/components/page for Sightly and foundation/components/page for JSP)
Steps to customize the basic page properties and including dynamic DropDownList to the dialog.
/apps/training/components/page-content/ will be referred as the page rendering component path in the post.
Classic UI:
Copy /libs/foundation/components/page/dialog to /apps/training/components/page-content/Rename the new node to required name e.g. custom
Copy /libs/foundation/components/page/tab_basic to /apps/training/components/page-content/
Rename /apps/training/components/page-content/tab_basic to required name e.g tab_custom
Remove all the nodes under /apps/training/components/page-content/tab_custom/items
Change path value in the node /apps/training/components/page-content/dialog/items/tabs/items/custom to /apps/training/components/page-content/tab_custom.infinity.json
Change title property of the node /apps/training/components/page-content/tab_custom to required value e.g Custom
Save All configurations
Open the page from site Admin(e.g. http://localhost:4502/cf#/content/training-site/en.html), now the new tab(Custom) will be added to the page properties with empty panel
Adding a textfield to the custom panel:
Create a new node of type cq:Widget under /apps/training/components/page-content/tab_custom/itemsName | Type | Value |
---|---|---|
xtype | String | textfield |
name | String | ./fieldName e.g. ./customtext |
fieldLabel | String | Enter the field lable |
Save All configurations - open the page(e.g. http://localhost:4502/cf#/content/training-site/en.html), the new textfield will be displayed under Custom tab.
Adding a dynamic DropDownList:
Create a servlet that returns the JSON data.import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.apache.sling.commons.json.JSONArray;
import org.apache.sling.commons.json.JSONObject;
import org.apache.felix.scr.annotations.Properties;
@Service(value = Servlet.class)
@Component(immediate = true, metatype = true)
@Properties({
@Property(name = "sling.servlet.paths", value = "/services/getCountries"),
@Property(name = "service.description", value = "returns list of countries"),
@Property(name = "label", value = "GetCountryList") })
public class GetCountryList extends SlingSafeMethodsServlet{
private static final long serialVersionUID = 1180258251365536303L;
@Override
protected void doGet(SlingHttpServletRequest request,SlingHttpServletResponse response) throws ServletException,IOException {
try{
response.setContentType("application/json; charset=utf-8");
response.setCharacterEncoding("UTF-8");
JSONArray contryJsonArray = new JSONArray();
JSONObject jsonObject = new JSONObject();
jsonObject.put("text", "US").put("value", "United States");
contryJsonArray.put(jsonObject);
jsonObject = new JSONObject();
jsonObject.put("text", "UK").put("value", "United Kingdom");
contryJsonArray.put(jsonObject);
response.getWriter().write(contryJsonArray.toString());
}catch(Exception e){
}
}
}
Create a new node of type cq:Widget under /apps/training/components/page-content/tab_custom/items
Add the following properties to the new node
Name | Type | Value |
---|---|---|
xtype | String | selection |
name | String | ./fieldName e.g. ./customtext |
fieldLabel | String | Enter the field label |
type | String | select |
options | String | Servlet path that returns JSON data (e.g. /services/getCountries) |
Save All Configurations - open the page(e.g. http://localhost:4502/cf#/content/training-site/en.html), the new DropDownList will be displayed under Custom tab.
Touch UI:
Copy /libs/foundation/components/page/cq:dialog to /apps/training/components/page-content
Copy /apps/training/components/page-content/cq:dialog/content/items/tabs/items/basic and paste to /apps/training/components/page-content/cq:dialog/content/items/tabs/items
Rename the node name to required value e.g Custom
Change the jcr:title property of the node e.g Custom
Remove nodes that are not required and create/rename nodes as required(better remove all the nodes under /apps/training/components/page-content/cq:dialog/content/items/tabs/items/custom/items/column/items and create the required nodes).
Adding a Dynamic Dropdownlist:
Create a servlet that will return the DataSource
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.servlet.ServletException;
import org.apache.felix.scr.annotations.sling.SlingServlet;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceMetadata;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.apache.sling.api.wrappers.ValueMapDecorator;
import com.adobe.granite.ui.components.ds.DataSource;
import com.adobe.granite.ui.components.ds.SimpleDataSource;
import com.adobe.granite.ui.components.ds.ValueMapResource;
@SlingServlet(resourceTypes = "/services/getCountryList")
public class GetCountryListServlet extends SlingSafeMethodsServlet{
private static final long serialVersionUID = 1180258251365536303L;
@Override
protected void doGet(SlingHttpServletRequest request,SlingHttpServletResponse response) throws ServletException,IOException {
try{
ResourceResolver resolver = request.getResourceResolver();
List<Resource> countryList = new ArrayList<Resource>();
ValueMap valueMap = new ValueMapDecorator(new HashMap<String, Object>());
valueMap.put("value","United States");
valueMap.put("text","US");
countryList.add(new ValueMapResource(resolver, new ResourceMetadata(), "nt:unstructured", valueMap));
valueMap = new ValueMapDecorator(new HashMap<String, Object>());
valueMap.put("value","United Kingdom");
valueMap.put("text","UK");
countryList.add(new ValueMapResource(resolver, new ResourceMetadata(), "nt:unstructured", valueMap));
DataSource dataSource = new SimpleDataSource(countryList.iterator());
request.setAttribute(DataSource.class.getName(), dataSource);
}catch(Exception e){
e.printStackTrace();
}
}
}
The servlet is not registered with the above code in AEM 6.4, @Component is expected for the servlet.
Servelet - AEM 6.4
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.servlet.*;
import org.apache.felix.scr.annotations.sling.SlingServlet;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceMetadata;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.apache.sling.api.wrappers.ValueMapDecorator;
import com.adobe.granite.ui.components.ds.DataSource;
import com.adobe.granite.ui.components.ds.SimpleDataSource;
import com.adobe.granite.ui.components.ds.ValueMapResource;
import org.osgi.service.component.annotations.Component;
import org.osgi.framework.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component(service=Servlet.class,
property={
Constants.SERVICE_DESCRIPTION + "=Get Country List Servlet",
"sling.servlet.methods=" + "GET",
"sling.servlet.resourceTypes="+ "/services/getCountryList"
})
public class GetCountryListServlet extends SlingSafeMethodsServlet{
private static final long serialVersionUID = 1180258251365536303L;
Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
protected void doGet(SlingHttpServletRequest request,SlingHttpServletResponse response) throws ServletException,IOException {
try{
logger.error("inside...");
ResourceResolver resolver = request.getResourceResolver();
List<Resource> countryList = new ArrayList<Resource>();
ValueMap valueMap = new ValueMapDecorator(new HashMap<String, Object>());
valueMap.put("value","United States");
valueMap.put("text","US");
countryList.add(new ValueMapResource(resolver, new ResourceMetadata(), "nt:unstructured", valueMap));
valueMap = new ValueMapDecorator(new HashMap<String, Object>());
valueMap.put("value","United Kingdom");
valueMap.put("text","UK");
countryList.add(new ValueMapResource(resolver, new ResourceMetadata(), "nt:unstructured", valueMap));
DataSource dataSource = new SimpleDataSource(countryList.iterator());
logger.error("dataSource...");
request.setAttribute(DataSource.class.getName(), dataSource);
}catch(Exception e){
logger.error("error..."+e.getMessage());
e.printStackTrace();
}
}
}
The servlet is not registered with the above code in AEM 6.4, @Component is expected for the servlet.
Servelet - AEM 6.4
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.servlet.*;
import org.apache.felix.scr.annotations.sling.SlingServlet;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceMetadata;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.apache.sling.api.wrappers.ValueMapDecorator;
import com.adobe.granite.ui.components.ds.DataSource;
import com.adobe.granite.ui.components.ds.SimpleDataSource;
import com.adobe.granite.ui.components.ds.ValueMapResource;
import org.osgi.service.component.annotations.Component;
import org.osgi.framework.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component(service=Servlet.class,
property={
Constants.SERVICE_DESCRIPTION + "=Get Country List Servlet",
"sling.servlet.methods=" + "GET",
"sling.servlet.resourceTypes="+ "/services/getCountryList"
})
public class GetCountryListServlet extends SlingSafeMethodsServlet{
private static final long serialVersionUID = 1180258251365536303L;
Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
protected void doGet(SlingHttpServletRequest request,SlingHttpServletResponse response) throws ServletException,IOException {
try{
logger.error("inside...");
ResourceResolver resolver = request.getResourceResolver();
List<Resource> countryList = new ArrayList<Resource>();
ValueMap valueMap = new ValueMapDecorator(new HashMap<String, Object>());
valueMap.put("value","United States");
valueMap.put("text","US");
countryList.add(new ValueMapResource(resolver, new ResourceMetadata(), "nt:unstructured", valueMap));
valueMap = new ValueMapDecorator(new HashMap<String, Object>());
valueMap.put("value","United Kingdom");
valueMap.put("text","UK");
countryList.add(new ValueMapResource(resolver, new ResourceMetadata(), "nt:unstructured", valueMap));
DataSource dataSource = new SimpleDataSource(countryList.iterator());
logger.error("dataSource...");
request.setAttribute(DataSource.class.getName(), dataSource);
}catch(Exception e){
logger.error("error..."+e.getMessage());
e.printStackTrace();
}
}
}
Create a node(e.g. customlist) with type nt:unstructured under /apps/training/components/page-content/cq:dialog/content/items/tabs/items/custom/items/column/items
Add the following properties to the new node
Name | Type | Value |
---|---|---|
emptyText | String | selection |
name | String | ./fieldName e.g. ./customlist |
fieldLabel | String | Enter the field label |
sling:resourceType | String | granite/ui/components/foundation/form/select |
Create a node with name datasource and type nt:unstructured under the node created in the previous step
Enter the below property
Name | Type | Value |
---|---|---|
sling:resourceType | String | Servlet Path(e.g. /services/getCountryList) |
Save All Configurations - open the page(e.g. http://localhost:4502/editor.html/content/training-site/en.html), the new fileds/DropDownList will be displayed under Custom tab.
HI,
ReplyDeleteThanks for the info. When we are overriding the dialog(in TOUCH UI) in our page component with only one tab, why we are seeing the OOTB components tabs as well in page properties.
Thanks,
Pradeep