AEM is a proven framework for application delivery. Intuitive authoring features and HTL (formerly Sightly) driven content views make it easy to put together pages served from an AEM environment. The standard component strategy is great, but AEM offers more flexibility in how you use authored content. AEM Content Services allows authored content to be consumed via a headless CMS approach.
Content fragments offer discrete pieces of text and/or markup, and the Assets API provides references to your assets (including content fragments), all consumable by external apps as JSON.
In a mature DAM, you’ll find you have some images and fragments that are appropriate for external exposure and some that are not. AEM provides Asset Collections to expose specific assets and organize those assets in a simplified way. You can add assets or fragments to a collection from anywhere in the DAM and easily view all items within.
To provide these collections as a part of your headless CMS solution, you need to be able to display them in the JSON response provided by the Sling GET servlet. The out-of-the-box fragments implementation allows you to use content references, but that only serves as a reference to the collection. It doesn’t provide the content within. Using the familiar Sling model + HTL component pattern, the code here enables access to the elements in a collection:
There are a few things to note here, as this is a Sling model you have access to the configured dialog properties via the ValueMapValue annotation. Via the Source annotation, you have access to a resource resolver which is managed by Sling.
The key method in this class is setCollectionProperties(). This writes the selected collection(s) content as properties of the component instance node.
Invoke the above model in your HTL template via:
<sly data-sly-use.addcollections="com.sample.core.models.IncludeCollectionsModel"> ${addcollections.setCollectionProperties} </sly>
The component dialog needs 2 key fields, the content type to define the type of content the collection contains, and the path to the collection’s JCR node. Note, the collection node path may need to be obtained via CRX/DE and provided to your authors. Organizing your collections under /content/dam/collections in a logical manner and providing a dialog option to filter them is an exercise I leave to you.
Your dialog should resemble this: https://github.com/PRFTAdobe/AEM-Tutorials/blob/main/sample/ui.apps/src/main/content/jcr_root/apps/sample/components/include-collections/_cq_dialog/.content.xml
Allow the component (or its group name) in your template policy. With these items in place, you can add the component to a page and configure its dialog to use the required collection. Knowledge of the collection’s purpose and content is helpful to select the right content type. Select images in the content-type field to just list out the assets in the collection:
With one or multiple instances of this component configured in a page, request the page as HTML. This will set the property values in each component instance, to include the collections/associated content in the JSON response for the page.
Note, you need to call the page HTML any time the collections are updated, in order to include those latest updates into the JSON response. There is a means to avoid this and have the JSON automatically update whenever collections change. This will be provided in part 2, so be on the lookout for it!
Then, you (or a third party) can call the page with the following selectors and extension: model.tidy.json. DAM collections are referenced via the component and included in the JSON representation of the page’s content! A mobile app or another third party can easily parse and extract the values from these objects, for inclusion in a view they control.
Using this technique, you can realize the dual benefits of AEM’s touch UI authoring features and headless CMS features. This gives power to your content authors for generating content usable in and out of AEM!
this pathfield is not picking collection path with resource type = dam/collection.
and adding in the html is not working. ModifiableValueMap was throwing error so added import as import org.apache.sling.api.resource.ModifiableValueMap;