April 11, 2020
Estimated Post Reading Time ~

Loading Components Dynamically

AEM provides a great WYSIWYG interface to drag and drop a discrete set of components onto a page. This interface, however, does not account for components that need to be added to a page dynamically. This post will discuss how to add sets of components to a page programatically based on custom logic.

A previous post discussed strategies for componentizing AEM content, and featured a new “bestsellers” component for the Geometrixx demo site. Here, that example will be used and built upon. To follow along, first install the completed package from the last walkthrough.

Step 1: Create a set of “bestseller” component instances in a new page

The Best Seller component being dragged onto the Products page

After installing the package linked above, the Geometrixx products page lists a static set of “best sellers” that are dragged onto the page as whole, discrete components. The goal for this example is to have the bestseller components loaded into this page dynamically, as opposed to being permanently stored there. So we will need to create another “permanent home” page for all best seller components to be defined, stored, and modified.

Create a new page using AEM’s Site Builder. Because this page is not going to be directly viewed by end users, details like name and location won’t matter. For this demo, a page is created in this location:

http://localhost:4502/cf#/content/geometrixx/en/products/bestsellers.html

Create this page, open it, and add 5-10 bestseller component instances that have been customized to display various shapes. This page may require edits to the design dialog of its par. Also, depending on the page type and template used, formatting might be gone. This is perfectly fine, because this page is only used as a location for authors to create and customize instances of bestsellers for the purpose of loading them elsewhere.


While creating and modifying these bestsellers, it may be easier start by copying and pasting nodes from within CRXDE in the /content folder location after the first few are created.

Bestseller component instances in the /content node

Step 2: Create a “loader” component to fetch content “content” components
Following the same pattern as the bestseller component, create a new component called “bestsellerloader”. This new component will have the responsibility of fetching existing instances of bestseller components from a node in the content repository, then displaying them on the currently-viewed page. In a real application, bestsellerloader would contain configuration configuration options such as the maximum number of items to display, or the location of “storage” node where those items are located. These options would be controlled by design and edit dialogs. This example hardcodes everything for convenience.

bestsellerloader.jsp (1)
<%@include file="/libs/foundation/global.jsp"%>
<%@page import="java.lang.Iterable"%>
<%@page session="false" %>
<%
String bestsellerPath = "/content/geometrixx/en/products/bestsellers/jcr:content/par/";
Iterable<Resource> bestsellers = resourceResolver.getResource(bestsellerPath).getChildren();
for (Resource bestseller : bestsellers) {
%>
<sling:include path="<%= bestseller.getPath() %>" />
<%
}
%>


With a hardcoded link to the node in which the bestseller components are stored, a resourceResolver object, already instantiated and available, can be used to return the list of nodes. Looping through these, a <sling:include> tag can be used to inject them directly into the page. Note that the sling:include tag is processed during page rendering, and users will only see the final result. Other options for loading components after page load will be demonstrated in future posts.

Step 3: Add logic and formatting to bestsellerloader
Add the bestsellerloader component to the Geometrixx Products Page, in place of the original, individually added components. When viewing the page, the bestseller components will now be loaded dynamically from the bestsellerloader component. One thing that is lost from the original page, however, is the two-column row formatting. Fortunately, we can inject that formatting back into bestsellerloader.

bestsellerloader.jsp (2)
<%@include file="/libs/foundation/global.jsp"%>
<%@page import="java.lang.Iterable"%>
<%@page session="false" %>
<%
String bestsellerPath = "/content/geometrixx/en/products/bestsellers/jcr:content/par/";
Iterable<Resource> bestsellers = resourceResolver.getResource(bestsellerPath).getChildren();
int index = 0;
for (Resource bestseller : bestsellers) {
if (index % 2 == 0){
%>

<div class="parsys_column cq-colctrl-lt0">
<%
}
%>

<div class="parsys_column cq-colctrl-lt0-c<%= index % 2 %>">
<sling:include path="<%= bestseller.getPath() %>" />
</div>
<%
if (index % 2 == 1){
%>
</div>
<%
}
index++;
}
%>


The above approach should be considered a “quick and dirty” solution, as we’re not directly utilizing AEM’s built-in column controls, nor are we making the bestsellerloader very flexible for reuse on other pages that aren’t intended for 2-column formatting. While much of that can be cleaned up, it does illustrate the point that control over how the component instance’s HTML is laid out has been taken away from the page, and given to the loader. Sometimes the limitation of this necessitates the creation of multiple loader components to fit the needs and logic of particular pages.

Summary: While the previous post demonstrated how to create individual components for direct inclusion on a page, this demo shows how to indirectly load component sets from the location. This was accomplished by creating an author-only “storage” page, where new instances of components were to be created, and a “loader” component, which will pull these instances from the storage page to a user-facing page.



By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.