I am using the front-end pipeline, thus not using clientlibs but having the css and js served from the CDN via links like:
<script src="http://127.0.0.1:4173/theme.js" type="module"></script>
<link href="http://127.0.0.1:4173/theme.css" type="text/css" as="style" rel="preload stylesheet">
This works on normal pages with experience fragments and it works in AEM author when authoring an experience fragment as well, via this code in the xfpage components customheaderlibs.html:
<sly data-sly-use.page="com.adobe.cq.wcm.core.components.models.Page"
data-sly-list="${page.htmlPageItems}">
<script data-sly-test="${item.location.name == 'header'}"
data-sly-element="${item.element.name @ context='unsafe'}"
data-sly-attribute="${item.attributes}"></script>
</sly>
However, I have now created a new Sling model for our custom page component like this:
@Model(
adaptables = SlingHttpServletRequest.class,
adapters = Page.class,
resourceType = "mycompany/components/corporate/page",
defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL
)
public class CorporatePageImpl implements Page {
@Self @Via(type = ResourceSuperType.class)
private Page delegate;
In this sling model, I do delegate the other Page methods as such:
@Override
public List<HtmlPageItem> getHtmlPageItems() {
return delegate.getHtmlPageItems();
}
But now the styles (those .css and .js links above) have vanished in AEM author when editing an experience fragment. What appears to be happening is that in customheaderlibs.html, the <sly data-sly-use.page="com.adobe.cq.wcm.core.components.models.Page" is returning my CorporatePageImpl Sling model, but then my delegated getHtmlPageItems method ends up throwing a NullPointerException. The delegate is not null, it is also an instance of CorporatePageImpl. I noticed on normal pages where this still works, it's an instance of PageImpl.
What is happening here and how can I get my styles when authoring experience fragments again?
Topics help categorize Community content and increase your ability to discover relevant content.
Views
Replies
Total Likes
Hi @jakebowers,
In Experience Fragments, it looks like Sling model adaptation resolves again to your CorporatePageImpl (possibly due to the resource type resolution in the XF context), creating an infinite loop until a null delegate is hit.
Try adding a guard to prevent self-delegation and see if it works
To avoid infinite recursion and ensure your delegate is not the same type as your model, add this in CorporatePageImpl:
@PostConstruct
protected void init() {
if (delegate instanceof CorporatePageImpl) {
// Avoid self-delegation loop
delegate = null;
}
}
You can also check more robustly using:
@PostConstruct
protected void init() {
if (delegate != null && delegate.getClass().equals(this.getClass())) {
delegate = null;
}
}
And in getHtmlPageItems(), guard it:
@Override
public List<HtmlPageItem> getHtmlPageItems() {
return delegate != null ? delegate.getHtmlPageItems() : Collections.emptyList();
}
OR
Instead of relying on Sling’s @Via(type = ResourceSuperType.class), explicitly adapt to the core PageImpl:
@PostConstruct
protected void init() {
delegate = request.adaptTo(com.adobe.cq.wcm.core.components.models.Page.class);
}
Then, inject the request:
@Self
private SlingHttpServletRequest request;
This ensures you're getting the correct core Page implementation regardless of resource type - avoiding cycles.
Hi SantoshSai, thank you for your suggestions, I tried them both.
In your first suggestion, the delegate in getHtlmItems was null, so just got the empty list and no styles.
In your second suggestion, the delegate again adapts to CorporatePageImpl, and so the same problem.
It might be the right idea though, if there are multiple sling objects that implement the Page interface, it seems to always find mine and it would be good to be able to tell it to find Adobe's.
request.adaptTo(com.adobe.cq.wcm.core.components.internal.models.v3.PageImpl.class) doesn't work though as that class is not exposed/available.
I wouldn't expect to be the first person to create a Sling object for a custom page component, so I'm not sure if I may have something else setup incorrectly, but I'm definitely missing styles in AEM author when editing experience fragments. The reason I created the new Sling object is to modify the getCanonicalLink behaviour to exclude the canonical link on certain pages.
Views
Replies
Total Likes
Hi,
For those that may be having the same or similar issue, I ended up fixing this by creating a new empty interface:
@ConsumerType
public interface CustomPage extends Page {
}
And then had my new Sling model use that. Notice both the implements CustomPage and the adapters = CustomPage.class
@Model(
adaptables = SlingHttpServletRequest.class,
adapters = CustomPage.class,
resourceType = "mycompany/components/corporate/page",
defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL
)
public class CorporatePageImpl implements CustomPage {
In this way, AEM doesn't get confused on which Page implementation to use.
Even though the documentation shows direct implementation:
https://experienceleague.adobe.com/en/docs/experience-manager-core-components/using/developing/custo...
The above is possibly cleaner to avoid issues like this.
Views
Replies
Total Likes
Views
Likes
Replies
Views
Likes
Replies