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