In AEM component dialog, we often implement multifield which comprise of multiple widgets. Here we would cover multifield which would store values in json format using:
- Coral 3 multifield
- acs-aem-commons package
- javax.json.JsonObject API: Since, org.apache.sling.commons.json.JSONObject has been deprecated.
STEP 1: Create a component.
STEP 2: Create component dialog with multifield comprising of:
- textfield
- pathbrowser
Add acs-commons-nested=”JSON_STORE” to the multifield
<?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="Navigation" sling:resourceType="cq/gui/components/authoring/dialog">
<content jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/container">
<items jcr:primaryType="nt:unstructured">
<tabs 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">
<navigationitems jcr:primaryType="nt:unstructured" jcr:title="Navigation Items" sling:resourceType="granite/ui/components/foundation/section">
<layout jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns" margin="{Boolean}false"/>
<items jcr:primaryType="nt:unstructured">
<column jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/container">
<items jcr:primaryType="nt:unstructured">
<navigationitems jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/form/multifield" class="full-width" fieldDescription="Click 'Add field' to add a new item" fieldLabel="Navigation Items">
<field jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/form/fieldset" acs-commons-nested="JSON_STORE" name="./navigationItems">
<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">
<label jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/form/textfield" fieldLabel="Label" name="./linktext"/>
<link jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/form/pathbrowser" fieldLabel="Link" name="./linkURL" rootPath="/content"/>
</items>
</column>
</items>
</field>
</navigationitems>
</items>
</column>
</items>
</navigationitems>
</items>
</tabs>
</items>
</content>
</jcr:root>
STEP 3: Add dependencies to the pom.xml
Incase, the AEM doesn’t export javax.json.JsonObject API, then you would have to import the bundles in AEM.
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-json_1.0_spec</artifactId>
<version>1.0-alpha-1</version>
</dependency>
<dependency>
<groupId>org.apache.johnzon</groupId>
<artifactId>johnzon-core</artifactId>
<version>1.0.0</version>
</dependency>
STEP 4: Create Sling Model to access multifield values. The values returned as a List would be iterated in Component’s sightly to display links.
Bean to hold a link’s details:
/** * NavigationItem for Links. */
public class NavigationItem {
private String linktext;
private String linkURL;
public NavigationItem(String linktext, String linkURL){
this.linktext = linktext;
this.linkURL = linkURL;
}
public String getLinktext() {
return linktext;
}
public void setLinktext(String linktext) {
this.linktext = linktext;
}
public String getLinkURL() {
return linkURL;
}
public void setLinkURL(String linkURL) {
this.linkURL = linkURL;
}
}
Sling Model to gather details of all configured links:
package blog.techrevel.core.models;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonReader;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.Optional;
import blog.techrevel.NavigationItem;
/** * A model bean for the link component */
@Model(adaptables = Resource.class)
public class ProductNavigationModel {
private static final String LINK_URL = "linkURL";
private static final String LINK_TEXT = "linktext";
@Inject
@Optional
private String[] navigationItems;
private List<NavigationItem> list;
@PostConstruct protected void init() {
if (navigationItems != null) {
this.list = new ArrayList<>();
for (String linkJsonString : navigationItems) {
try (StringReader stringReader = new StringReader(linkJsonString);
JsonReader jsonReader = Json.createReader(stringReader)) {
JsonObject linkJsonObject = jsonReader.readObject();
String linkPath = linkJsonObject.getString(LINK_URL);
list.add(new NavigationItem(linkJsonObject.getString(LINK_TEXT), linkPath));
}
}
}
}
public List<NavigationItem> getList() {
return list;
}
}
STEP 5: Render links in Component’s sightly by accessing the Sling Model
<div data-sly-use.linkModel="blog.techrevel.core.models.ProductNavigationModel">
<!--/*Links*/-->
<sly data-sly-repeat.item="${linkModel.list}">
<a href="${item.linkURL}"> ${item.linktext}</a>
</sly>
<sly data-sly-test="${!linkModel.list}">Navigation Component</sly></div>
Verified on AEM 6.3 with acs-aem-commons package version 3.9.0