Accessing Component Policies in AEM through the Component Sling Model

Problem Statement:

How can I utilize component policies chosen at the template level to manage the visibility of specific field content within the component’s Sling model code?

Introduction:

AEM has integrated component policies as a pivotal element of the editable template feature. This functionality empowers both authors and developers to provide options for configuring the comprehensive behavior of fully-featured components, including deciding which fields to display, hide, or customize. This configuration is carried out at the template level, facilitating reuse across various templates or template-specific customizations.

Furthermore, AEM introduces a robust styling feature that empowers frontend developers to manage the visual appearance and user interface of components. This grants authors the capability to tailor the look and feel of the component.

Let’s illustrate this with an AEM core component as an example:

Requirement:

In a previous discussion, we outlined a step-by-step process for Accessing Component Policies in AEM at the Component Dialog Level and Sightly code. However, a situation has arisen a question where the field has already been authored on multiple pages, and we now need to avoid displaying this field on pages where it has already been authored. How can this be achieved using the Sling model?

Solution:

This can be achieved at the Sling model level in two ways:

  1. By adapting to Out of the Box (OOTB) “ContentPolicyManager” as shown below:
package com.adobe.cq.wcm.core.components.internal.models.v1;

import com.adobe.cq.export.json.ExporterConstants;
import com.adobe.cq.wcm.core.components.models.Teaser;
import com.day.cq.wcm.api.designer.Style;
import com.day.cq.wcm.api.policies.ContentPolicy;
import com.day.cq.wcm.api.policies.ContentPolicyManager;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Exporter;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.*;

@Model(adaptables = SlingHttpServletRequest.class, resourceType = TeaserModel.RESOURCE_TYPE)
@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME , extensions = ExporterConstants.SLING_MODEL_EXTENSION)
public class TeaserModel {
    public final static String RESOURCE_TYPE = "core/wcm/components/teaser/v1/teaser";

    @Self
    private SlingHttpServletRequest request;

    @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL)
    private String pretitle;

    @SlingObject
    protected Resource resource;

    private boolean pretitleHidden = false;

    public String getPretitle() {
        ContentPolicyManager policyManager = request.getResourceResolver().adaptTo(ContentPolicyManager.class);
        if (policyManager != null) {
            ContentPolicy currentPolicy = policyManager.getPolicy(resource, request);
            if (currentPolicy != null) {
                pretitleHidden = currentPolicy.getProperties().get(Teaser.PN_PRETITLE_HIDDEN, pretitleHidden);
            }
        }
        if(!pretitleHidden){
            return pretitle;
        }
        return StringUtils.EMPTY;
    }
}

2. By Injecting Out of the Box (OOTB) “currentStyle” using “ScriptVariable” as shown below:

package com.adobe.cq.wcm.core.components.internal.models.v1;

import com.adobe.cq.export.json.ExporterConstants;
import com.adobe.cq.wcm.core.components.models.Teaser;
import com.day.cq.wcm.api.designer.Style;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.models.annotations.Exporter;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy;
import org.apache.sling.models.annotations.injectorspecific.ScriptVariable;
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;

@Model(adaptables = SlingHttpServletRequest.class, resourceType = TeaserModel.RESOURCE_TYPE)
@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME , extensions = ExporterConstants.SLING_MODEL_EXTENSION)
public class TeaserModel {
    public final static String RESOURCE_TYPE = "core/wcm/components/teaser/v1/teaser";
    
    @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL)
    private String pretitle;

    @ScriptVariable
    protected Style currentStyle;

    private boolean pretitleHidden = false;

    public String getPretitle() {
        pretitleHidden = currentStyle.get(Teaser.PN_PRETITLE_HIDDEN, pretitleHidden);
        if(!pretitleHidden){
            return pretitle; 
        }
        return StringUtils.EMPTY;
    }
}

One significant advantage of employing the Sling model for this requirement is the flexibility it offers in implementing and manipulating business logic before delivering results. As demonstrated in the example above, injecting ScriptVariable allows for a more streamlined approach, eliminating the need for extra lines of code such as adaptation, resource resolution, and null checks. The Sling model code dynamically manages the visibility of the “pretitle” field based on the “pretitleHidden” property in the “currentStyle.”

Accessing Component Policies in AEM at the Component Sightly Level

How can I access component policies selected at the template level to control the visibility of specific field content in the component’s Sightly code?

AEM has integrated component policies as a pivotal element of the editable template feature. This functionality empowers both authors and developers to provide options for configuring the comprehensive behavior of fully-featured components, including deciding which fields to display, hide, or customize. This configuration is carried out at the template level, facilitating reuse across various templates or template-specific customizations.

Furthermore, AEM introduces a robust styling feature that empowers frontend developers to manage the visual appearance and user interface of components. This grants authors the capability to tailor the look and feel of the component.

Let’s illustrate this with an AEM core component as an example:

Requirement:

In a previous discussion, we outlined a step-by-step process for Accessing Component Policies in AEM at the Component Dialog Level. However, a situation has arisen a question where the field has already been authored on multiple pages, and we now need to avoid displaying this field on pages where it has already been authored. How can we achieve this?

If the “hidePretitle” checkbox is unchecked at the policy level, the Sightly code should display the content.

Policy unchecked
Sightly Display content


If the “hidePretitle” checkbox is checked at the policy level, the Sightly code should hide the content.

Policy checked
Sightly hide content

Solution:

This can be accomplished at the Sightly level by utilizing the Out of the Box (OOTB) implicit object called “currentStyle,” which implements “com.day.cq.wcm.api.designer.Style” as demonstrated below:

${!currentStyle.pretitleHidden}
<sly data-sly-template.pretitle="${@ teaser}">

    <p class="cmp-teaser__pretitle" data-sly-test.pretitle="${!currentStyle.pretitleHidden}">${teaser.pretitle}</p>

</sly>

This Sightly code dynamically controls the visibility of the “pretitle” based on the “pretitleHidden” property in the “currentStyle.”

Sightly code