3
votes

In our AEM 6.2 project, I ran to a scenario where I need to config a navigation in one page (let call this Homepage), all of the other pages can use home navigation config or use their own navigation config values.

I decided to use live copy because the clone pages can cancel the linked properties at any time and use their own values. But there is two problem with this approach:

  1. Users must set the template for clone pages by edit their jcr: content/sling:resourceType and jcr: content/cq: template because the navigation is used in all pages and our web uses about 5+ templates.
  2. Live copy does no allowed clone pages are children of source pages. But I was required to make web structure like this :

    Home
       |_ Page 1
                |_ Page 1.1
       |_ Page 2
       |_ Page 3
    

Live copy maybe not suitable for this situation, we change to use HTL ${inheritedPageProperties}, this solve the template and structure issue but it creates two new problems:

  1. Inherited properties in property config dialog of child page will be blank (because they are not set and called via ${inheritedPageProperties} )

  2. If users change properties in "Page 1" page, "Page 1.1" (and Page 1.1.1, etc ...) will use these values (Because ${inheritedPageProperties} search the upper nodes to get value).

What our client want are :

  • All page can use navigation setting only from the homepage or their own page (use home page by default).
  • If use homepage properties, these values must show in their config dialog.
  • Try to avoid config template in CRXDE Lite
  • The website must have the parent-child structure

How can I achieve these requirements?

1
so the inheritance you are looking for is only between descendants and root (Page 1) and not the whole Tree? for example if you had P1 -> P1.1 -> P1.1.1 you want P1.1.1 to inherit ONLY from P1 and override it if P1.1.1 has it's on values set?Ahmed Musallam
yes, this is what i'm looking for.Hai Hoang

1 Answers

2
votes

You can achieve this with a simple Sling Model and Sling's CompositeValueMap

CompositeValueMap docs state:

An implementation of the ValueMap based on two ValueMaps: - One containing the properties - Another one containing the defaults to use in case the properties map does not contain the values. In case you would like to avoid duplicating properties on multiple resources, you can use a CompositeValueMap to get a concatenated map of properties.

We can use this by supplying the descendant's value map (the current page's) then finding the correct ancestor and supplying its properties valuemap as the defaults.

for the purposes of this question, I always assume that 2rd descendant from root is always the ancestor (you can find your ancestor according to your requirnments)

package com.sample.helpers;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageManager;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.wrappers.CompositeValueMap;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.OSGiService;
import org.apache.sling.models.annotations.injectorspecific.Self;

import javax.annotation.PostConstruct;

@Model(adaptables = Resource.class)
public class CustomInheritedPageProperties
{

    ValueMap inheritedProperties;

    @Self
    Resource currentResource;

    @OSGiService
    PageManager pageManager;

    @PostConstruct
    protected void init() {
        // get the current page, or the "descendant"
        Page descendant = pageManager.getContainingPage(currentResource);

        /* You have to add your custom logic to get the ancestor page.
         * for this question's purposes, I'm always assuming it's the 3rd decendant of root
         * more here: https://helpx.adobe.com/experience-manager/6-2/sites/developing/using/reference-materials/javadoc/com/day/cq/wcm/api/Page.html#getParent(int)
         */
        Page ancestor = descendant.getParent(2);

        // create a CompositeValueMap where the properties are descendant's and the defaults are ancestor's
        inheritedProperties = new CompositeValueMap(descendant.getProperties(), ancestor.getProperties());
    }

    public ValueMap getInheritedProperties()
    {
        return inheritedProperties;
    }
}

Now you can use this as follows

<sly data-sly-use.propHelper="com.sample.helpers.CustomInheritedPageProperties">>/sly>
<!--/* someProp here refers to the property you wish to get (inherited, of course)*/-->
<h1>propHelper.inheritedProperties.someProp</h1>