Fetch Multifield Values using Sling Model

Published
In accordance with specific project requirements, there might be a need to incorporate Multifield within the component dialog. Let's explore how to retrieve Multifield data and effectively utilize it in HTL.
Here is a sample cq_dialog allowing AEM authors to enter multiple article items.
article / _cq_dialog / .content.xml
<relatedArticles jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/multifield" fieldLabel="Related Articles" composite="{Boolean}true" required="{Boolean}true"> <field jcr:primaryType="nt:unstructured" sling:resourceType = "granite/ui/components/coral/foundation/container" name="./relatedArticles"> <items jcr:primaryType="nt:unstructured"> <articleTitle jcr:primaryType="nt:unstructured" sling:resourceType = "granite/ui/components/coral/foundation/form/textfield" fieldLabel="Article Title" name="./title"/> <articleDetailsPage jcr:primaryType="nt:unstructured" sling:resourceType="cq/gui/components/coral/common/form/pagefield" fieldLabel="Article Details Page" name="./detailsPage" rootPath="/content/aem-demo"/> </items> </field> </relatedArticles>
For demonstration purposes, we've included an option for the article title. However, you can also fetch the title directly from the page itself, depending on your project requirements.
After authoring the component dialog, multifield data is stored in the content repository as shown below.
content / aem-demo / home
<article jcr:primaryType="nt:unstructured" sling:resourceType="aem-demo/components/article" title="Adobe AEM Community Advisor" author="Mahedi Sabuj"> <relatedArticles jcr:primaryType="nt:unstructured"> <item0 jcr:primaryType="nt:unstructured" title="Experience League Community" detailsPage="/content/aem-demo/us/en/aem/community"/> </relatedArticles> </article>
To retrieve this data, Sling Model can be utilized. Using @ChildResource annotation injectors, we can adapt them to the target type (e.g., ArticleItem) and populate them with all child resources of the resource identified by the specified name.
components / model / Article.java
@Model( adaptables = SlingHttpServletRequest.class, adapters = { Article.class }, resourceType = { Article.RESOURCE_TYPE }, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL ) @Exporter( name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION) public class Article { protected static final String RESOURCE_TYPE = "aem-demo/components/article"; @Getter @ValueMapValue String title; @Getter @ValueMapValue String author; @Getter @ChildResource List<ArticleItem> relatedArticles; }
components / model / ArticleItem.java
@Model( adaptables = Resource.class, adapters = { ArticleItem.class }, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL ) public class ArticleItem { @Getter @ValueMapValue String title; @Getter @ValueMapValue String detailsPage; }
To showcase related articles in the component's HTML, you can iterate through the list of articles using data-sly-list and display their information accordingly.
article / article.html
<div data-sly-use.article="com.aem.demo.core.components.models.Article" data-sly-use.templates="core/wcm/components/commons/v1/templates.html" data-sly-test.hasContent="${article.title}" class="article__inner"> <div data-sly-list.item="${article.relatedArticles}"> <a href="${item.detailsPage @ context = 'uri'}"> ${item.title} </a> </div> </div> <sly data-sly-call="${templates.placeholder @ isEmpty = !hasContent, classAppend = 'cmp-article'}"/>
You can externalize the detailsPage value according to your business requirements.