aem

Retrieving values from multifield component in HTL in AEM 6.5


I have a multifield component following this format

<?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="Awards List"
    sling:resourceType="cq/gui/components/authoring/dialog">
    <content
        jcr:primaryType="nt:unstructured"
        sling:resourceType="granite/ui/components/coral/foundation/container">
        <layout
            jcr:primaryType="nt:unstructured"
            sling:resourceType="granite/ui/components/coral/foundation/tabs"
            type="-nav"/>
        <items jcr:primaryType="nt:unstructured">
            <awards
                jcr:primaryType="nt:unstructured"
                jcr:title="Awards Properties"
                sling:resourceType="granite/ui/components/foundation/section">
                <layout
                    jcr:primaryType="nt:unstructured"
                    sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns"/>
                <items jcr:primaryType="nt:unstructured">
                    <column
                        jcr:primaryType="nt:unstructured"
                        sling:resourceType="granite/ui/components/coral/foundation/container">
                        <items jcr:primaryType="nt:unstructured">
                            <description
                                jcr:primaryType="nt:unstructured"
                                sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
                                fieldLabel="Description"
                                name="./description"/>
                            <awards
                                jcr:primaryType="nt:unstructured"
                                sling:resourceType="granite/ui/components/coral/foundation/form/multifield"
                                composite="{Boolean}true"
                                fieldLabel="Awards">
                                <field
                                    jcr:primaryType="nt:unstructured"
                                    sling:resourceType="granite/ui/components/coral/foundation/container"
                                    name="./awards">
                                    <items jcr:primaryType="nt:unstructured">
                                        <column
                                            jcr:primaryType="nt:unstructured"
                                            sling:resourceType="granite/ui/components/coral/foundation/container">
                                            <items jcr:primaryType="nt:unstructured">
                                                <awardtype
                                                    jcr:primaryType="nt:unstructured"
                                                    sling:resourceType="granite/ui/components/coral/foundation/form/select"
                                                    fieldDescription="Select Award Type"
                                                    fieldLabel="Award Type"
                                                    name="./type">
                                                    <items jcr:primaryType="nt:unstructured">
                                                        <gold
                                                            jcr:primaryType="nt:unstructured"
                                                            text="gold"
                                                            value="gold"/>
                                                        <silver
                                                            jcr:primaryType="nt:unstructured"
                                                            text="silver"
                                                            value="silver"/>
                                                        <bronze
                                                            jcr:primaryType="nt:unstructured"
                                                            text="bronze"
                                                            value="bronze"/>
                                                        <other
                                                            jcr:primaryType="nt:unstructured"
                                                            text="other"
                                                            value="other"/>
                                                    </items>
                                                </awardtype>
                                                <award
                                                    jcr:primaryType="nt:unstructured"
                                                    sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                                                    fieldDescription="Name of Award"
                                                    fieldLabel="Award Name"
                                                    name="./award"/>
                                            </items>
                                        </column>
                                    </items>
                                </field>
                            </awards>
                        </items>
                    </column>
                </items>
            </awards>
        </items>
    </content>
</jcr:root>

And I'm trying to just output the contents of the multifield into a list. And I'm attempting to do so with

<ul data-sly-list="${properties.awards}">
    <li>${item.type}</li>
</ul>

But it doesn't render anything. As a test I did

<ul data-sly-list="${[1,2,3,4]}">
    <li>${item}</li>
</ul>

Which did work. Looking online I found resources like https://helpx.adobe.com/experience-manager/using/aem65_coral_resourcetypes.html#UseaDataSourceObjecttopopulateaSelectfield

But they seem to be using Java classes to generate the multifield and I'm hoping that's not necessary. I don't need any extra logic all I'm trying to do is display the values of the fields.

Is there something I'm doing wrong? Does using multifields require making a Java class to handle it?

EDIT: I've tried getting the content using a javascript object by having a js file with the contents

"use strict";

use(function () {
    var description = granite.resource.properties["description"];
    var awards = granite.resource.properties["awards"];

    return {
        description: description,
    };
});

and using

<div data-sly-use.awardsObject="awardslist.js">
    <p>
        ${awardsObject.description}
        ${awardsObject.awards}
    </p>
</div>

But I can't get awards to return anything. I've tried stringifying the awards object to see if I get any data, but I get none.


Solution

  • It is probably because you are using a composite multifield (look at the property composite="{Boolean}true" against the multifield) which generally handles the form content as composite and creates child nodes under the current component to hold the property values.

    Quoting from the docs

    true to handle the form content value as composite.

    Composite multifield supports nesting another multifield (composite or not). However, non-composite one doesn’t support nesting.

    For example, given the name property of field is addresses, and the descendant fields have following name property values:

    street1
    street2  
    postcode 
    city/name 
    city/state  
    city/country/name
    gps/lat 
    gps/long
    

    it would save the following structure in the repository:

     + addresses   + item0
         - street1
         - street2
         - postcode
         + city
           - name
           - state
           + country
             - name
         + gps
           - lat
           - long   + item1
         - street1
         - street2
         - postcode
         + city
           - name
           - state
           + country
             - name
         + gps
           - lat
           - long
    

    Since the properties object only holds the properties of the current resource, ${properties.awards} would be null and hence it doesn't display anything.

    It would be easier to create either a Sling Model or Java / Javascript Use API class to get the list and then use it in the HTL file.

    Sample JS Use API

    "use strict";
    
    use(function () {
        var awards = resource.getChild("awards").listChildren();
    
        return {
            awards: awards,
        };
    });
    

    Sample HTL code

    <sly data-sly-use.children="children.js">
        <ul data-sly-list.award="${children.awards}">
            <li>${award.type}</li>
        </ul>
    <sly>
    

    Kindly note that the properties object, which is an instance of ValueMap only returns the properties of the current resource. Since the multifield values are stored as child resources, you need to access the child resource first before accessing its properties.