Deep diving into Sling models PT6

17 juli 2020by Dylan Reniers

The final chapter: Customizing AEM Core Components

Nowadays you won’t find a lot of projects anymore that don’t make use of the AEM Core Components, and with good reason. The core components provide some nice out-of-the-box functionalities and best practices that help to decrease the development effort required to build a website. If you haven’t already, you can find documentation here (https://docs.adobe.com/content/help/en/experience-manager-core-components/using/introduction.html) and the open source git repository here (https://github.com/adobe/aem-core-wcm-components).

Because we make so much use of them, we often find ourselves creating overlays for these components to extend their look & feel, but what if we want to modify the underlying backend code? In this blog post we’ll discuss how we can do that, using the Sling delegation pattern.

Please note that in order to make use of this feature, you need to have the Sling Models API 1.3.4 or higher and the Sling Models Impl 1.4.0 or higher.

When would we want to use this?

Imagine the following scenario: you must build a component to share your pages on social media. Great! Nothing we must do for that, because there is a sharing component in the core components.

Unfortunately for you, the business wants people to be able to share on Facebook and Twitter and the default implementation only works for Facebook and Pinterest. You don’t want to create a model to just copy/paste whatever was made in the core components project and add your own logic to that. To prevent us from having to do this, the Sling delegation pattern comes to the rescue.

So how does it work?

The Sling delegation pattern is used to inject an instance of our super type model into the current model. This means that we can create a model that extends from our resourceSuperType’s model and add our own custom logic to that. Let me show you an example to make this a bit clearer:

We have a component called Page Headline, with resource type myproject/components/pageHeadline, that extends the Title component from the Adobe core components project, by having the following .content.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
          jcr:primaryType="cq:Component"
          jcr:title="Page Headline"
          jcr:description="Display Page Heading"
          sling:resourceSuperType="core/wcm/components/title/v2/title"
          componentGroup="My Project"/>

This means that we currently have the following component structure:

Inside the pageHeadline.html file we call for the PageHeadline model, using a data-sly-use. The PageHeadline looks like this:

@Model(adaptables = SlingHttpServletRequest.class, adapters = Title.class, resourceType = "myproject/components/pageHeadline")
public class PageHeadline implements Title {

    @ScriptVariable
    private Page currentPage;

    @Self @Via(type = ResourceSuperType.class)
    private Title title;

    @Override
    public String getText() {
        return currentPage.getTitle();
    }

    @Override
    public String getType() {
        return title.getType();
    }
}

The key is the combination of the @Self and the @Via(type = ResourceSuperType.class) annotations. First, we must implement the same interface as the interface that is used in the HTL of our resourceSuperType component, in our case the Title interface. This is yet another reason why we should create interfaces for our model. For more reasons why, check my first blog post of this series “Creating an interface for a model”. With this in mind, we have the following class diagram as a result:

Next we must add the interface to the list of adapters in the @Model annotation. This is so that Sling knows it can take the PageHeadline class if it finds a data-sly-use attribute which value is equal to the Title interface. The reason why I set the word ‘can’ in italic is because this is not always the case, only when the PageHeadline class is the best matching model class. Now what makes this model “the best matching model”? This is thanks to the resourceType attribute of the @Model annotation. Since the value we specify there is an exact match to the resource type of the component that called for this model (myproject/components/pageHeadline), we know that Sling will use this model in the myproject/components/pageHeadline component.

This is also a reason why we should properly annotate our models with a resourceType attribute if it is the go-to model for a component. More ways on how to property annotate your Sling models can be found in the blog post “How to properly annotate your Sling models”.

So, all we have left to do is to implement all the interfaces of that Title interface. For all the methods that we don’t want to touch, we can just call title.doMethod and only code something in the methods we want to override. In this case we have overridden the getText method but left the getType method untouched.

I hope this has been informative to you and that it might help you if you want to customize some of the core components, not only from an HTL perspective, but also from a backend perspective.

CONTACTHoofdkantoor
Klaverbladstraat 7a b5,
3560 Lummen - BE
JONG EN HIP?Gebruik onze social links
U kan ons ook contacteren via
onze verschillende social media kanalen.
JOBSOok Joker worden?
Bezoek onze carrière pagina voor
openstaande opportuniteiten.
ContactHoofdkantoor
Klaverbladstraat 7a b5, 3560 Lummen - BE
JONG & HIP?Gebruik onze Social links
U kan ons ook contacteren via onze verschillende social media kanalen.