May 15, 2020
Estimated Post Reading Time ~

Extending the ACS AEM Commons Generic List to Support Multiple Fields



The Adobe Experience Manager ACS Commons Generic List facilitates authorable Title / Value pairs that can be used to populate dropdowns from a centrally authored location. The functionality of the Generic List is limited to the Title and Value pairs, but there could be other use cases for centrally managed metadata that can be easily chosen from a dropdown. This example will extend the Generic List to manage metadata for organizational units/departments.

The Generic List implementation is final, so not extendable, but the underlying interface only relies on the jcr:title/value pairs to be present. We will use this and add additional fields that we can adaptTo to our own implementation. The Generic List was built before the prevalence of Sling Models, so for this example, we will try to simplify this by utilizing Sling Models.

Example Implementation on Github: https://github.com/msullivan-r2i/acs-genericlist-extension

Implementing the List Extension

department.java
This is the Sling Model that will add email and phone values to the existing jcr:title and value fields. It implements GenericList.Item, however, this is not strictly required. The mechanisms that populate the dropdown will not use the Department implementation and rely on the underlying jcr:title & value fields and utilize the ACS implementation.

@Model(adaptables=Resource.class)
public class Department implements GenericList.Item {

static final String TITLE_PREFIX = NameConstants.PN_TITLE + ".";

@Inject
private Resource resource;

@Inject @Named("jcr:title") @Default(values="")
public String title;

@Inject @Default(values="")
public String value;

@Inject @Default(values="")
public String phone;

@Inject @Default(values="")
public String email;

public String getTitle() {
return title;
}

public String getTitle(Locale locale) {
/* see full file */
}

private String getLocalizedTitle(Locale locale) {
return resource.getValueMap().get(TITLE_PREFIX + locale.toString().toLowerCase(), String.class);
}

public String getValue() {
return value;
}

public String getPhone() {
return phone;
}

public String getEmail() {
return email;
}
}
department-generic-list.html
This renders the item in the Generic List authoring page. The ACS Implementation uses JSP and not Sling Models, but this is a little simpler.


<sly data-sly-use.department="com.example.core.genericlist.Department">
<li>
<span data-sly-test="${!department.title}" style="color: red;">Please enter a title</span>
<sly data-sly-test="${department.title}">
Title: ${department.title} <br />
Value: ${department.value} <br />
Phone: ${department.phone} <br />
Value: ${department.email} <br />
</sly>
</li>
</sly>
dialog.xml 

The Generic List is still Classic UI only, so we keep the jcr:title and value fields and add our email and phone fields.
<?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" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="cq:Dialog"
title="Department - Generic List Item"
xtype="panel">
<items jcr:primaryType="cq:WidgetCollection">
<title
jcr:primaryType="cq:Widget"
fieldLabel="Title"
name="./jcr:title"
xtype="textfield"/>
<value
jcr:primaryType="cq:Widget"
fieldDescription="This is typically the text used internally or for URL generation"
fieldLabel="Value"
name="./value"
xtype="textfield"/>
<phone
jcr:primaryType="cq:Widget"
fieldLabel="Phone"
name="./phone"
xtype="textfield"/>
<email
jcr:primaryType="cq:Widget"
fieldLabel="Email Address"
name="./email"
xtype="textfield"/>
</items>
<listeners
jcr:primaryType="nt:unstructured"
afterrender="function() { ACS.CQ.GenericListItem.addTitleFields(this); }"/>
</jcr:root>

Usage
Department Helper

The DepartmentHelper provides two methods, one to get a specific Department model given a value. The other to give a list of all of the models.

A department and department sample components are in the example project.
Department Component

The department component shows how to implement the dialog field to allow an author to choose a department from a dropdown. It then utilizes a WCMUsePojo helper to display the details of the selected department.

department/cq:dialog
We are referencing the ACS genericlist/datasource ui component to populate the dropdown, so this requires jcr:title and value fields be present for each item.

<department
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/select"
fieldLabel="Department"
name="./department">
<datasource
jcr:primaryType="nt:unstructured"
sling:resourceType="acs-commons/components/utilities/genericlist/datasource"
path="/etc/acs-commons/lists/departments" />
</department>
department.html
The DepartmentHelper takes the value of the selected department from the dropdown and returns an adapted Department model.

<div class="cmp-department"
data-sly-use.departmentHelper="${'com.example.core.genericlist.DepartmentHelper' @ value=properties.department }"
data-sly-test.department="${departmentHelper.department}">
<h1>${department.title}</h1>
<ul>
<li>${department.phone}</li>
<li>${department.email}</li>
</ul>
</div>
<h1 data-sly-test="${!department}">Select a Department</h1>
Departments Component
The department component iterates over all of the departments in the list in node order.

departments.html

<div class="cmp-departments"
data-sly-use.departmentHelper="com.example.core.genericlist.DepartmentHelper"
data-sly-test.departments="${departmentHelper.allDepartments}"
data-sly-test.hasDepartments="${departments.size > 0}">
<div data-sly-list.department="${departments}">
<h1>${department.title}</h1>
<ul>
<li>${department.phone}</li>
<li>${department.email}</li>
</ul>
</div>
</div>
<h1 data-sly-test="${!hasDepartments}">Add departments to the department generic list named <pre>/etc/acs-commons/lists/departments</pre></h1>
Optional Implementation
The example also creates a new template that can be placed under /etc/acs-commons/genericlist and an /etc/designs/acs-genericlist-example design definition that allows our department-generic-list component to be added to that page template. There is also a page component that simply extends the acs genericlist page component to give the design something unique to bind to.

This is optional and the extended generic list item could be allowed through the standard design ui.

i18N

This implementation doesn’t consider I18n, and the ACS list seems to do this through the dictionary. If this is a requirement, perhaps moving these out of /etc and into /content/../locale could allow for translations of this metadata as long as the values stayed the same.

Source: https://aemhq.com/posts/extending-the-acs-aem-commons-generic-list-to-support-multiple-fields/



By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.