dialogadobeaemslinghtl

AEM 6.4 - How to read multifield from design dialog using Sling model?


I have created a component with a design dialog and policy. I can read basic properties of the design dialog but am confused on what to do with multifield.

Design dialog (check headerPrimaryLinks)

<?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="Header"
    sling:resourceType="cq/gui/components/authoring/dialog">
    <content
        jcr:primaryType="nt:unstructured"
        sling:resourceType="granite/ui/components/coral/foundation/container">
        <items jcr:primaryType="nt:unstructured">
            <tabs
                jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/coral/foundation/tabs"
                maximized="{Boolean}true">
                <items jcr:primaryType="nt:unstructured">
                    <properties
                        jcr:primaryType="nt:unstructured"
                        jcr:title="Main"
                        sling:resourceType="granite/ui/components/coral/foundation/container"
                        margin="{Boolean}true">
                        <items jcr:primaryType="nt:unstructured">
                            <heading
                                jcr:primaryType="nt:unstructured"
                                sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                                fieldLabel="Heading"
                                name="./heading"/>
                            <logoAltText
                                jcr:primaryType="nt:unstructured"
                                sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                                fieldLabel="Logo Alt Text"
                                name="./alttext"/>
                        </items>
                    </properties>
                    <!-- <styletab
                        jcr:primaryType="nt:unstructured"
                        sling:resourceType="granite/ui/components/coral/foundation/include"
                        path="/mnt/overlay/cq/gui/components/authoring/dialog/style/tab_design/styletab"/> -->
                    <primaryLinks
                        jcr:primaryType="nt:unstructured"
                        jcr:title="Primary Links"
                        sling:resourceType="granite/ui/components/coral/foundation/container"
                        margin="{Boolean}true">
                        <items jcr:primaryType="nt:unstructured">
                            <link
                                jcr:primaryType="nt:unstructured"
                                sling:resourceType="granite/ui/components/coral/foundation/form/multifield"
                                composite="{Boolean}true"
                                fieldDescription="Click '+' to add a new link">
                                <field
                                    jcr:primaryType="nt:unstructured"
                                    sling:resourceType="granite/ui/components/coral/foundation/form/fieldset"
                                    name="./headerPrimaryLinks">
                                    <items jcr:primaryType="nt:unstructured">
                                        <column
                                            jcr:primaryType="nt:unstructured"
                                            sling:resourceType="granite/ui/components/coral/foundation/container">
                                            <items jcr:primaryType="nt:unstructured">
                                                <title
                                                    jcr:primaryType="nt:unstructured"
                                                    sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                                                    fieldLabel="Title"
                                                    name="./title"/>
                                                <linkURL
                                                    jcr:primaryType="nt:unstructured"
                                                    sling:resourceType="granite/ui/components/coral/foundation/form/pathbrowser"
                                                    fieldLabel="Link to"
                                                    name="./linkURL"
                                                    rootPath="/content"/>
                                            </items>
                                        </column>
                                    </items>
                                </field>
                            </link>
                        </items>
                    </primaryLinks>
                </items>
            </tabs>
        </items>
    </content>
</jcr:root>

Header.java class

import javax.annotation.PostConstruct;

import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.Self;
import org.apache.sling.models.annotations.injectorspecific.SlingObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.day.cq.wcm.api.policies.ContentPolicy;
import com.day.cq.wcm.api.policies.ContentPolicyManager;

@Model(adaptables = Resource.class)
public class Header {
    private final Logger logger = LoggerFactory.getLogger(getClass());

    @SlingObject
    private ResourceResolver resourceResolver;

    @Self
    protected Resource resource;

    private String heading,
                   altText;

    @PostConstruct
    protected void init() {
        ContentPolicyManager policyManager = resourceResolver.adaptTo(ContentPolicyManager.class);

        if (policyManager != null) {
            ContentPolicy contentPolicy = policyManager.getPolicy(resource);

            if (contentPolicy != null) {
                ValueMap properties = contentPolicy.getProperties();

                // I can read these fine but how do I read a multifield?
                heading = (String) properties.get("heading");
                altText = (String) properties.get("alttext");
            }
        }
    }

    /**
    * Returns heading from design dialog.
    * 
    * @return heading
    */
    public String getHeading() {
        return heading;
    }

    /**
    * Returns alttext (logo alt text) from design dialog.
    * 
    * @return altText
    */
    public String getAltText() {
        return altText;
    }
}

In the component, I can read Strings like:

<sly data-sly-use.header="com.uchealth.aem.core.models.Header">
    ${header.heading}
</sly>

or just

${currentStyle.heading}

Here is how it looks in CRX:

header
-  policy_1547171225060
    - headerPrimaryLinks
      - item0
      - item1
      - item2
    - headerSecondaryLinks
      - item0
      - item1
      - item2

How do I read a multifield to use data-sly-list in my HTL?


Solution

  • I have not tested this, so I'm not sure it works 100%. First of all, you will need a SlingModel to represent the multifield items:

    @Model(adaptables = Resource.class)
    public class HeaderPrimaryLink {
    
        @Inject
        private Resource resource;
    
        @Inject
        @Optional
        private String title;
    
        @Inject
        @Optional
        private String linkURL;
    
        public String getTitle() {
            return title;
        }
    
        public String getLinkURL() {
            return linkURL;
        }
    }
    

    Then, in your "Header" model you can have a list of "HeaderPrimaryLink" models that will contain all the items filled in the multifield:

    ...
        private String heading,
                   altText;
    
        private List<HeaderPrimaryLink> links;
    
        @PostConstruct
    ...
    

    I'm not sure how is the multifield being stored under the policy node (if you can post an image of the nodes in the CRX would help), but assuming the multifield is stored as nodes under the policy resource, I would try to get that node and fill the list (something like this):

        Resource multifieldResource = resourceResolver.getResource(contentPolicy.getPath() + "/headerPrimaryLinks");
        if (multifieldResource != null) {
            for (Resource currentResource : multifieldResource.getChildren()) {
                links.add(currentResource.adaptTo(HeaderPrimaryLink.class));
            }
        }
    

    And then in the HTML:

    <sly data-sly-use.header="com.uchealth.aem.core.models.Header">
        <ul data-sly-list="${header.links}">
            <li>
               <a target="_blank" href="${item.linkURL}">${item.title}</a>
            </li>
        </ul>
    </sly>
    

    Hope that helps.