Close Menu
    DevStackTipsDevStackTips
    • Home
    • News & Updates
      1. Tech & Work
      2. View All

      Sunshine And March Vibes (2025 Wallpapers Edition)

      May 16, 2025

      The Case For Minimal WordPress Setups: A Contrarian View On Theme Frameworks

      May 16, 2025

      How To Fix Largest Contentful Paint Issues With Subpart Analysis

      May 16, 2025

      How To Prevent WordPress SQL Injection Attacks

      May 16, 2025

      Microsoft has closed its “Experience Center” store in Sydney, Australia — as it ramps up a continued digital growth campaign

      May 16, 2025

      Bing Search APIs to be “decommissioned completely” as Microsoft urges developers to use its Azure agentic AI alternative

      May 16, 2025

      Microsoft might kill the Surface Laptop Studio as production is quietly halted

      May 16, 2025

      Minecraft licensing robbed us of this controversial NFL schedule release video

      May 16, 2025
    • Development
      1. Algorithms & Data Structures
      2. Artificial Intelligence
      3. Back-End Development
      4. Databases
      5. Front-End Development
      6. Libraries & Frameworks
      7. Machine Learning
      8. Security
      9. Software Engineering
      10. Tools & IDEs
      11. Web Design
      12. Web Development
      13. Web Security
      14. Programming Languages
        • PHP
        • JavaScript
      Featured

      The power of generators

      May 16, 2025
      Recent

      The power of generators

      May 16, 2025

      Simplify Factory Associations with Laravel’s UseFactory Attribute

      May 16, 2025

      This Week in Laravel: React Native, PhpStorm Junie, and more

      May 16, 2025
    • Operating Systems
      1. Windows
      2. Linux
      3. macOS
      Featured

      Microsoft has closed its “Experience Center” store in Sydney, Australia — as it ramps up a continued digital growth campaign

      May 16, 2025
      Recent

      Microsoft has closed its “Experience Center” store in Sydney, Australia — as it ramps up a continued digital growth campaign

      May 16, 2025

      Bing Search APIs to be “decommissioned completely” as Microsoft urges developers to use its Azure agentic AI alternative

      May 16, 2025

      Microsoft might kill the Surface Laptop Studio as production is quietly halted

      May 16, 2025
    • Learning Resources
      • Books
      • Cheatsheets
      • Tutorials & Guides
    Home»Development»Mastering Page Properties With Granite Render Conditions and Context-Aware Configuration

    Mastering Page Properties With Granite Render Conditions and Context-Aware Configuration

    July 29, 2024

    From Static to Dynamic: The Evolution of Template Management

    Do you remember the days of static templates? We had a plethora of templates, each with its own page components and CQ dialogs. It was a maintenance nightmare! 

    But then came editable templates, and everything changed. With this new approach, we can define a single-page component and create multiple templates from it. Sounds like a dream come true, right? 

    But there’s a catch. What if we need different dialogs for different templates? Do we really need to create separate template types for each one? That would mean maintaining multiple template types and trying to keep track of which template uses which type. Not exactly the most efficient use of our time. 

    Managing Page Properties in AEM

    In this post, we’ll explore the challenges of template management and how we can overcome them using Granite render conditions and context-aware configurations. 

    When managing page properties, we’re often faced with a dilemma. While context-aware configurations are ideal for setting up configurations at the domain or language level, they fall short when it comes to managing individual pages. 

    The usual go-to solution is to update the Page Properties dialog, but this approach has its own set of limitations. So, what’s a developer to do? 

    Fortunately, there’s a solution that combines the power of Granite render conditions with the flexibility of context-aware configurations. 

    What is Granite Render Condition? 

    Render condition is just conditional logic to render a specific section of the component UI. If you want a more detailed description, you can read Adobe’s official documentation. 

    A Real-World Use Case Using Both Granite Render Condition and Context-Aware Configuration

    Say we want to display and hide the page properties tab based on the template name, which can be configured using context-aware configuration without any hardcoded code.   

    First, we’d need to build the CAC which will contain fields for adding the template names and tab path to show.   

    We will create a service for context-aware configuration which will read config and provide the mapping. 

    public interface PageTabsMappingService {
    List<PageTabsMappingConfig> getPageTabsMappingConfigList();

    }

    Here PageTabsMappingConfig is just a POJO bean class that consists of a page tab path and template path. 

    @Data
    public class PageTabsMappingConfig {
    private String templatePath;
    private String tabPath;
    }

    Now let’s create a context-aware configuration implementation class, which will consist of a template path and tabs path configuration ability. 

    We want this to be more author-friendly, so we will be using a custom data source. This data source can be found in this blog post. 

    For this example, we need two data sources, one for template path and one for tab paths.  

     So finally, our configuration will look like this:

    @Configuration(label = “Page Tabs Mapping Configuration”, description = “Page Tabs Mapping Config”, property =
    {EditorProperties.PROPERTY_CATEGORY + “=TemplateAndTabs”}, collection = true)
    public @interface PageTabsMappingConfiguration {

    @Property(label = “Select Template To Be Mapped”, description = “Select Template Name To Be Mapped”, property = {
    “widgetType=dropdown”,
    “dropdownOptionsProvider=templateDataSource”
    },order = 1)
    String getTemplatePath();

    @Property(label = “Select Tab to be mapped”, description = “Select Tab to be mapped”, property = {
    “widgetType=dropdown”,
    “dropdownOptionsProvider=tabDataSource”
    },order = 2)
    String getTabPath();

    }

    Now let’s implement Service to read this config. 

    public interface PageTabsMappingService {
    List<PageTabsMappingConfig> getPageTabsMappingConfigList(Resource resource);

    }
    @Component(service = PageTabsMappingService.class,
    immediate = true)
    @ServiceDescription(“Implementation For PageTabsMappingService “)
    @Slf4j
    public class PageTabsMappingServiceImpl implements PageTabsMappingService {

    @Override
    public List<PageTabsMappingConfig> getPageTabsMappingConfigList(final Resource resource) {

    final ConfigurationBuilder configurationBuilder = Optional.ofNullable(resource)
    .map(resource1 -> resource1.adaptTo(ConfigurationBuilder.class))
    .orElse(null);
    return new ArrayList<>(Optional
    .ofNullable(configurationBuilder)
    .map(builder -> builder
    .name(PageTabsMappingConfiguration.class.getName())
    .asCollection(PageTabsMappingConfiguration.class))
    .orElse(new ArrayList<>()))
    .stream().map(pageTabsMappingConfiguration ->new PageTabsMappingConfig(pageTabsMappingConfiguration.getTabPath(),pageTabsMappingConfiguration.getTemplatePath()))
    .collect(Collectors.toList());
    }
    }

    In the above code, we are reading context-aware configuration and providing the list for further use. 

    Now let us create render condition to show and hide tabs in page properties which will utilize the CAC mapping configuration. 

    We will be using the Sling Model for the same. This will be invoked whenever Page properties tabs are opened, in page editor mode, creation wizard, or on sites wizard. 

    @Model(adaptables = SlingHttpServletRequest.class)
    public class TabsRenderConditionModel {

    @Self
    private SlingHttpServletRequest request;

    @OSGiService
    private PageTabsMappingService pageTabsMappingService;

    /**
    * This is to set render condition for tabs.
    */
    @PostConstruct
    public void init() {

    final var resource = request.getResource()
    .getResourceResolver().getResource(“/content”);
    //We are considering root level site config since this will be global.
    //For multitenant environment you can add additional OSGI Config and use the path accordingly
    final List<PageTabsMappingConfig> tabRenderConfig =
    pageTabsMappingService.getPageTabsMappingConfigList(resource);
    final var name = Optional.ofNullable(request.getResource().getParent())
    .map(Resource::getName).orElse(StringUtils.EMPTY);
    final var props = (ValueMap) request.getAttribute(“granite.ui.form.values”);
    final var template = Optional.ofNullable(props)
    .map(props1 -> props1.get(“cq:template”, String.class))
    .orElse(StringUtils.EMPTY);

    final var renderFlag = tabRenderConfig.stream()
    .anyMatch(tabConfig ->
    BooleanUtils.and(new Boolean[]{StringUtils.equals(name, tabConfig.getTabName()),
    StringUtils.equals(template, tabConfig.getTemplatePath())}));

    request.setAttribute(RenderCondition.class.getName(),
    new SimpleRenderCondition(renderFlag));
    }

    }

    After reading template we simply check if this given tab name mapping exists or not. Based on that, using the simple render condition we are setting a flag for showing and hiding the tab. 

    Now it is time to use this Sling model in the actual render condition script file. In our project directory let’s assume /apps/my-project/render-conditions/tabs-renderconditions 

    Create tabs-renderconditions.html  

    And add content as: 

    <sly data-sly-use.tab=”com.mybrand.demo.models.TabsRenderConditionModel” />

    Build a customs tabs under the base page template folder as follows: 

    /apps/my-project/components/structure/page/base-page/tabs

    -landing-page-tab

    -home-page-tab

    -country-page-tab

    -state-page-tab

    -hero-page-tab

    And our cq:dialog will be referring the same as this:

    <?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″ xmlns:nt=”http://www.jcp.org/jcr/nt/1.0″
    jcr:primaryType=”nt:unstructured”>
    <content jcr:primaryType=”nt:unstructured”>
    <items jcr:primaryType=”nt:unstructured”>
    <tabs jcr:primaryType=”nt:unstructured”>
    <items jcr:primaryType=”nt:unstructured”>

    <additionalHeroPage
    jcr:primaryType=”nt:unstructured”
    sling:resourceType=”granite/ui/components/foundation/include”
    path=”/mnt/override/apps/my-project/components/structure/page/tabs/additional-hero-page”/>
    <additionalStatePage
    jcr:primaryType=”nt:unstructured”
    sling:resourceType=”granite/ui/components/foundation/include”
    path=”/mnt/override/apps/my-project/components/structure/page/tabs/additionalstatepage”/>
    </items>
    </tabs>
    </items>
    </content>
    </jcr:root>

    And our sample tab with render condition config will looks like this: 

    <additionalHeroPage
    cq:showOnCreate=”{Boolean}true”
    jcr:primaryType=”nt:unstructured”
    jcr:title=”Additional Hero Page Setting”
    sling:resourceType=”granite/ui/components/coral/foundation/fixedcolumns”>
    <items jcr:primaryType=”nt:unstructured”>
    <column
    jcr:primaryType=”nt:unstructured”
    sling:resourceType=”granite/ui/components/coral/foundation/container”>
    <items jcr:primaryType=”nt:unstructured”>
    <section1
    jcr:primaryType=”nt:unstructured”
    jcr:title=”Settings”
    sling:resourceType=”granite/ui/components/coral/foundation/form/fieldset”>
    <items jcr:primaryType=”nt:unstructured”>
    <testProperty
    cq:showOnCreate=”{Boolean}true”
    jcr:primaryType=”nt:unstructured”
    sling:resourceType=”granite/ui/components/coral/foundation/form/textfield”
    fieldDescription=”Test Property”
    fieldLabel=”Test Property”
    name=”./testProp”
    required=”{Boolean}true”>
    <granite:data
    jcr:primaryType=”nt:unstructured”
    cq-msm-lockable=”./testProp”/>
    </testProperty>
    </items>
    </section1>
    </items>
    </column>
    </items>
    <granite:rendercondition
    jcr:primaryType=”nt:unstructured”
    sling:resourceType=”my-project/render-conditions/tabs-renderconditions”/>
    </additionalHomePage>

    In the below Template and Tabs CAC configuration, the “Additional Home Page Setting” tab will be displayed in page properties when an author is opening a page created using the hero-page template. 

    Finally, when you open any page made with a configured template, like the Hero page in the image below, you can see the tabs configured for it. 

    More Helpful AEM Tips and Tricks

    I hope you have a better understanding of how to overcome some of the challenges of managing templates in AEM.

    For more AEM tips and tricks, keep up with us on our Adobe blog! 

    Source: Read More 

    Facebook Twitter Reddit Email Copy Link
    Previous ArticleGh0st RAT Trojan Targets Chinese Windows Users via Fake Chrome Site
    Next Article Encrypting and Decrypting Passwords Using Java in Selenium

    Related Posts

    Security

    Nmap 7.96 Launches with Lightning-Fast DNS and 612 Scripts

    May 17, 2025
    Common Vulnerabilities and Exposures (CVEs)

    CVE-2025-4610 – WordPress WP-Members Membership Plugin Stored Cross-Site Scripting Vulnerability

    May 17, 2025
    Leave A Reply Cancel Reply

    Continue Reading

    Distribution Release: MX Linux 23.6

    News & Updates

    Best antivirus for Mac in 2025: I tested your top software options

    News & Updates

    Building Your First Container with a HelloWorld Image using Docker CLI

    Development

    List All Folders in Mailbox – Exchange/O365/PowerShell

    Development

    Highlights

    Development

    How to Divide Two Variables in Bash Scripting

    July 3, 2024

    by George Whittaker Introduction Bash scripting is a powerful tool for automating tasks on Linux…

    Hackers Target Uyghurs and Tibetans with MOONSHINE Exploit and DarkNimbus Backdoor

    December 7, 2024

    Replicating CSS Object-Fit in WebGL: Optimized Techniques for Image Scaling and Positioning

    March 11, 2025

    Build an automated insight extraction framework for customer feedback analysis with Amazon Bedrock and Amazon QuickSight

    June 25, 2024
    © DevStackTips 2025. All rights reserved.
    • Contact
    • Privacy Policy

    Type above and press Enter to search. Press Esc to cancel.