AEM – Coral 2 multifield with acs-aem-commons JSON_STORE


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:

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

Leave a comment