AEM Nested Multifield Sling Model | Community
Skip to main content
Level 2
January 5, 2022

AEM Nested Multifield Sling Model

  • January 5, 2022
  • 1 reply
  • 8010 views

I'm attempting to write a multifield navigation component in AEM following this guide here:

https://blogs.perficient.com/2018/08/24/using-sling-models-with-nested-composite-mulitifields-in-aem-6-3/

I have it working fairly well using interfaces, but when I try to implement a class based approach AEM no longer seems to pick up my primaryLinks / secondaryLinks / tertiaryLinks content. From what I can tell in the AEM documentation here: https://sling.apache.org/documentation/bundles/models.html#collections it seems like it should be possible for the Sling Model to pick up the List just by using @586265. Am I missing something here? I've also attached an image of the content I'm attempting to work with along w/ code below.

 

CRX: 

 

Model w/ Interfaces (works) :

@Model( adaptables = {Resource.class}, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL) public interface Navigation { @Inject List<PrimaryLink> getPrimaryLinks(); @Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL) interface PrimaryLink { @Inject String getName(); @Inject List<SecondaryLink> getSecondaryLinks(); } @Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL) interface SecondaryLink { @Inject String getName(); @Inject List<TertiaryLink> getTertiaryLinks(); } @Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL) interface TertiaryLink { @Inject String getName(); } }



HTL:

 

<sly data-sly-use.model="com.havertys.core.models.Navigation"/> <sly data-sly-test.empty="${!model.primaryLinks}" /> <div data-sly-test="${wcmmode.edit && empty}" class="cq-placeholder" data-emptytext="${component.title}"></div> <sly data-sly-test="${!empty}"> <div> <ul data-sly-list.primaryLink="${model.primaryLinks}"> <li>${primaryLink.name} <ul data-sly-list.secondaryLink="${primaryLink.secondaryLinks}"> <li> <b>Secondary:</b> ${secondaryLink.name} <br/> <ul data-sly-list.tertiaryLink="${secondaryLink.tertiaryLinks}"> <li> <b>Tertiary: </b> ${tertiaryLink.name} </li> </ul> </li> </ul> </li> </ul> </div> </sly>



Class Based Model (Doesn't Work). I've also tried adding getters but that fails as well.

@Model( adaptables = {Resource.class}, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL) public class Navigation { @Inject private List<PrimaryLink> primaryLinks; @Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL) public class PrimaryLink { @Inject private String name; @Inject private List<SecondaryLink> secondaryLinks; } @Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL) public class SecondaryLink { @Inject private String name; @Inject private List<TertiaryLink> tertiaryLinks; } @Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL) public class TertiaryLink { @Inject private String name; } }



Dialog:

<?xml version="1.0" encoding="UTF-8"?> <!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~ Copyright 2021 Adobe ~ ~ Licensed under the Apache License, Version 2.0 (the "License"); ~ you may not use this file except in compliance with the License. ~ You may obtain a copy of the License at ~ ~ http://www.apache.org/licenses/LICENSE-2.0 ~ ~ Unless required by applicable law or agreed to in writing, software ~ distributed under the License is distributed on an "AS IS" BASIS, ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ~ See the License for the specific language governing permissions and ~ limitations under the License. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:granite="http://www.adobe.com/jcr/granite/1.0" jcr:primaryType="nt:unstructured" jcr:title="Navigation" sling:resourceType="cq/gui/components/authoring/dialog" extraClientlibs="[core.wcm.components.navigation.v1.editor]" helpPath="https://www.adobe.com/go/aem_cmp_navigation_v2" trackingFeature="core-components:navigation:v2"> <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"> <navigationLinksTab jcr:primaryType="nt:unstructured" jcr:title="Navigation Links" sling:resourceType="granite/ui/components/coral/foundation/container" margin="{Boolean}true"> <items jcr:primaryType="nt:unstructured"> <primaryLinks jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/multifield" composite="{Boolean}true" fieldLabel="Primary Links"> <field jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/container" name="./primaryLinks"> <items jcr:primaryType="nt:unstructured"> <name jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/textfield" emptyText="Name" fieldLabel="Primary Link Name" name="./name"/> <secondaryLinks jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/multifield" composite="{Boolean}true" fieldLabel="Secondary Links"> <field jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/container" name="./secondaryLinks"> <items jcr:primaryType="nt:unstructured"> <name jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/textfield" emptyText="Name" fieldLabel="Secondary Link Name" name="./name"/> <tertiaryLinks jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/multifield" composite="{Boolean}true" fieldLabel="Tertiary Links"> <field jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/container" name="./tertiaryLinks"> <items jcr:primaryType="nt:unstructured"> <name jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/textfield" emptyText="Name" fieldLabel="Tertiary Link Name" name="./name"/> </items> </field> </tertiaryLinks> </items> </field> </secondaryLinks> </items> </field> </primaryLinks> </items> </navigationLinksTab> <promotionTab jcr:primaryType="nt:unstructured" jcr:title="Products" sling:resourceType="granite/ui/components/coral/foundation/container" margin="{Boolean}true"> <items jcr:primaryType="nt:unstructured"> <columns jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns" margin="{Boolean}true"> <items jcr:primaryType="nt:unstructured"> <column jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/container"> <items jcr:primaryType="nt:unstructured"> <accessibilityLabel jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/textfield" fieldDescription="Value of an aria-label attribute for the navigation. Should be added if there is more than one navigation on the page." fieldLabel="Label" name="./accessibilityLabel" value=""/> </items> </column> </items> </columns> </items> </promotionTab> </items> </tabs> </items> </content> </jcr:root>





This post is no longer active and is closed to new replies. Need help? Start a new post to ask your question.

1 reply

lukasz-m
Community Advisor
Community Advisor
January 5, 2022

Hi @user00928, could you please try below implementation

 

@Model(adaptables = { Resource.class }, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL) public class Navigation { @Inject private List<PrimaryLink> primaryLinks; @Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL) public static class PrimaryLink { @Inject private String name; @Inject private List<SecondaryLink> secondaryLinks; } @Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL) public static class SecondaryLink { @Inject private String name; @Inject private List<TertiaryLink> tertiaryLinks; } @Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL) public static class TertiaryLink { @Inject private String name; } }

 

user00928Author
Level 2
January 5, 2022

Hey lukaszm -- thank you for the response! Unfortunately I'm getting the same result even after making classes static (picture attached of the value my debugger is showing for primaryLinks). 

 

lukasz-m
Community Advisor
Community Advisor
January 6, 2022

@user00928, I have run the code on my local instance and it looks to be working fine. It seems that you've set your debugger break-point on class level - which is too early. The new object of the class is not initialized yet. What you could try, is to set your break-point on some method inside your class, or temporary you could add below method and set the break-point inside of it, e.g. on if condition

 

@PostConstruct public void init() { if (primaryLinks != null) { System.out.println(primaryLinks.size()); } }

 

I hope this will allow you to verify if primaryLinks and other elements are created correctly. Also you can check what is the resource path that is used to create Navigation model.