I replicated in my code the navigation core component that uses the path
Solved! Go to Solution.
Views
Replies
Total Likes
You can readily use all the existing code by using Delegation https://experienceleague.adobe.com/docs/experience-manager-core-components/using/developing/customiz...
You just need to use @Via annotation. Following would not be required.
Views
Replies
Total Likes
Hello @NathanVieira
The WCM Core Sling Models are tied to specific resource types. Example:
public static final String RESOURCE_TYPE = "core/wcm/components/navigation/v1/navigation";
When Navigation 2 component was created in WCM core component, a dummy v2 Sling Model was also created, which is an extension of v1 https://github.com/adobe/aem-core-wcm-components/blob/main/bundles/core/src/main/java/com/adobe/cq/w...
For your implementation, you might have to create a Model, that binds to your component and then use the WCM Core Navigation component via Delegate pattern.
Views
Replies
Total Likes
I was able to create my model and bind to my component, and I need the same variables that the core component Navigation uses.
But i have these erros
Views
Replies
Total Likes
package com.myproject.core.models.impl;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import javax.annotation.PostConstruct;
import javax.mail.Quota.Resource;
import com.adobe.cq.wcm.core.components.internal.Utils;
import com.adobe.cq.wcm.core.components.util.AbstractComponentImpl;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.models.annotations.Exporter;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.Via;
import org.apache.sling.models.annotations.injectorspecific.OSGiService;
import org.apache.sling.models.annotations.injectorspecific.ScriptVariable;
import org.apache.sling.models.annotations.injectorspecific.Self;
import org.apache.sling.models.annotations.via.ResourceSuperType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.adobe.cq.export.json.ComponentExporter;
import com.adobe.cq.export.json.ExporterConstants;
import com.adobe.cq.wcm.core.components.internal.LocalizationUtils;
import com.adobe.cq.wcm.core.components.commons.link.LinkManager;
import com.adobe.cq.wcm.core.components.models.Navigation;
import com.adobe.cq.wcm.core.components.models.NavigationItem;
import com.day.cq.wcm.api.LanguageManager;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageFilter;
import com.day.cq.wcm.api.components.Component;
import com.day.cq.wcm.api.designer.Style;
import com.day.cq.wcm.msm.api.LiveRelationshipManager;
/**
* Navigation model implementation.
*/
@Model(adaptables = SlingHttpServletRequest.class,
adapters = {Navigation.class, ComponentExporter.class},
resourceType = {NavMenuHeaderImpl.RESOURCE_TYPE})
public class NavMenuHeaderImpl implements Navigation {
/**
* The resource navigation component resource type.
*/
public static final String RESOURCE_TYPE = "apps/myproject/components/atom_nav-header";
/**
* Name of the resource / configuration policy property that defines the accessibility label.
*/
private static final String PN_ACCESSIBILITY_LABEL = "accessibilityLabel";
/**
* The current request.
*/
@Self
private SlingHttpServletRequest request;
/**
* The link manager.
*/
@Self
private LinkManager linkManager;
/**
* The current page.
*/
@ScriptVariable
private Page currentPage;
/**
* The current style.
*/
@ScriptVariable
private Style currentStyle;
/**
* The language manager service.
*/
@OSGiService
private LanguageManager languageManager;
/**
* The relationship manager service.
*/
@OSGiService
private LiveRelationshipManager relationshipManager;
/**
* The accessibility label.
*/
@nullable
private String accessibilityLabel;
/**
* Number indicating how many levels below the navigation root the navigation should start.
*/
private int structureStart;
/**
* Number indicating how many levels below the navigation root should be included in the results.
* Use "-1" for no limit.
*/
private int structureDepth;
/**
* The root page from which to build the navigation.
*/
private Page navigationRootPage;
/**
* Placeholder for the list of results.
*/
private List<NavigationItem> items;
/**
* Initialize the model.
*/
@PostConstruct
private void initModel() {
ValueMap properties = this.resource.getValueMap();
structureDepth = properties.get(PN_STRUCTURE_DEPTH, currentStyle.get(PN_STRUCTURE_DEPTH, -1));
boolean collectAllPages = properties.get(PN_COLLECT_ALL_PAGES, currentStyle.get(PN_COLLECT_ALL_PAGES, true));
if (collectAllPages) {
structureDepth = -1;
}
if (currentStyle.containsKey(PN_STRUCTURE_START) || properties.containsKey(PN_STRUCTURE_START)) {
//workaround to maintain the content of Navigation component of users in case they update to the current i.e. the `structureStart` version.
structureStart = properties.get(PN_STRUCTURE_START, currentStyle.get(PN_STRUCTURE_START, 1));
} else {
boolean skipNavigationRoot = properties.get(PN_SKIP_NAVIGATION_ROOT, currentStyle.get(PN_SKIP_NAVIGATION_ROOT, true));
if (skipNavigationRoot) {
structureStart = 1;
} else {
structureStart = 0;
}
}
}
/**
* Get the effective navigation root page.
*
* @Return The effective navigation root page.
*/
private Page getNavigationRoot() {
if (this.navigationRootPage == null) {
String navigationRootPath = Optional.ofNullable(this.resource.getValueMap().get(PN_NAVIGATION_ROOT, String.class))
.orElseGet(() -> currentStyle.get(PN_NAVIGATION_ROOT, String.class));
this.navigationRootPage = LocalizationUtils.getLocalPage(navigationRootPath,
this.currentPage,
this.request.getResourceResolver(),
this.languageManager,
this.relationshipManager)
.orElseGet(() -> currentPage.getPageManager().getPage(navigationRootPath));
}
return this.navigationRootPage;
}
@Override
public List<NavigationItem> getItems() {
if (this.items == null) {
this.items = Optional.ofNullable(this.getNavigationRoot())
.map(navigationRoot -> getRootItems(navigationRoot, structureStart))
.orElseGet(Stream::empty)
.map(item -> this.createNavigationItem(item, getItems(item)))
.collect(Collectors.toList());
}
return Collections.unmodifiableList(items);
}
protected NavigationItem newNavigationItem(Page page, boolean active, boolean current, @notnull LinkManager linkManager, int level,
List<NavigationItem> children, String parentId, Component component) {
return new NavigationItemImpl(page, active, current, linkManager, level, children, parentId, component);
}
@Override
@nullable
public String getAccessibilityLabel() {
if (this.accessibilityLabel == null) {
this.accessibilityLabel = this.resource.getValueMap().get(PN_ACCESSIBILITY_LABEL, String.class);
}
return this.accessibilityLabel;
}
@notnull
@Override
public String getExportedType() {
return this.resource.getResourceType();
}
/**
* Builds the navigation tree for a {@code navigationRoot} page.
*
* @Param subtreeRoot The page for which to generate the sub-tree.
* @Return the list of collected navigation trees
*/
private List<NavigationItem> getItems(@NotNull final Page subtreeRoot) {
if (this.structureDepth < 0 || subtreeRoot.getDepth() - this.getNavigationRoot().getDepth() < this.structureDepth) {
Iterator<Page> childIterator = subtreeRoot.listChildren(new PageFilter());
return StreamSupport.stream(((Iterable<Page>) () -> childIterator).spliterator(), false)
.map(item -> this.createNavigationItem(item, getItems(item)))
.collect(Collectors.toList());
}
return Collections.emptyList();
}
/**
* Gets a stream of the top level of pages in the navigation.
*
* @Param navigationRoot The navigation root page.
* @Param structureStart The number of levels under the root page to begin collecting pages.
* @Return Stream of all descendant pages of navigationRoot that are exactly structureStart levels deeper.
*/
private Stream<Page> getRootItems(@NotNull final Page navigationRoot, final int structureStart) {
if (structureStart < 1) {
return Stream.of(navigationRoot);
}
Iterator<Page> childIterator = navigationRoot.listChildren(new PageFilter());
return StreamSupport.stream(((Iterable<Page>) () -> childIterator).spliterator(), false)
.flatMap(child -> getRootItems(child, structureStart - 1));
}
/**
* Create a navigation item for the given page/children.
*
* @Param page The page for which to create a navigation item.
* @Param children The child navigation items.
* @Return The newly created navigation item.
*/
private NavigationItem createNavigationItem(@NotNull final Page page, @notnull final List<NavigationItem> children) {
int level = page.getDepth() - (this.getNavigationRoot().getDepth() + structureStart);
boolean current = checkCurrent(page);
boolean selected = checkSelected(page, current);
return newNavigationItem(page, selected, current, linkManager, level, children, getId(), component);
}
/**
* Checks if the specified page is selected.
* A page is selected if it is either:
* <ul>
* <li>The current page; or,</li>
* <li>A page that redirects to the current page; or,</li>
* <li>The current page is a child of the specified page</li>
* </ul>
*
* @Param page The page to check.
* @Return True if the page is selected, false if not.
*/
private boolean checkSelected(@NotNull final Page page, boolean current) {
return current
|| this.currentPage.getPath().startsWith(page.getPath() + "/");
}
private boolean checkCurrent(@NotNull final Page page) {
return this.currentPage.equals(page)
|| currentPageIsRedirectTarget(page);
}
/**
* Checks if the specified page redirects to the current page.
*
* @Param page The page to check.
* @Return True if the specified page redirects to the current page.
*/
private boolean currentPageIsRedirectTarget(@NotNull final Page page) {
return currentPage.equals(Utils.resolveRedirects(page).getLeft());
}
}
My code below
// package com.myproject.core.models.impl;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import javax.annotation.PostConstruct;
import javax.mail.Quota.Resource;
import com.adobe.cq.wcm.core.components.internal.Utils;
import com.adobe.cq.wcm.core.components.util.AbstractComponentImpl;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.models.annotations.Exporter;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.Via;
import org.apache.sling.models.annotations.injectorspecific.OSGiService;
import org.apache.sling.models.annotations.injectorspecific.ScriptVariable;
import org.apache.sling.models.annotations.injectorspecific.Self;
import org.apache.sling.models.annotations.via.ResourceSuperType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.adobe.cq.export.json.ComponentExporter;
import com.adobe.cq.export.json.ExporterConstants;
import com.adobe.cq.wcm.core.components.internal.LocalizationUtils;
import com.adobe.cq.wcm.core.components.commons.link.LinkManager;
import com.adobe.cq.wcm.core.components.models.Navigation;
import com.adobe.cq.wcm.core.components.models.NavigationItem;
import com.day.cq.wcm.api.LanguageManager;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageFilter;
import com.day.cq.wcm.api.components.Component;
import com.day.cq.wcm.api.designer.Style;
import com.day.cq.wcm.msm.api.LiveRelationshipManager;
/**
* Navigation model implementation.
*/
@Model(adaptables = SlingHttpServletRequest.class,
adapters = {Navigation.class, ComponentExporter.class},
resourceType = {NavMenuHeaderImpl.RESOURCE_TYPE})
public class NavMenuHeaderImpl implements Navigation {
/**
* The resource navigation component resource type.
*/
public static final String RESOURCE_TYPE = "apps/myproject/components/atom_nav-header";
/**
* Name of the resource / configuration policy property that defines the accessibility label.
*/
private static final String PN_ACCESSIBILITY_LABEL = "accessibilityLabel";
/**
* The current request.
*/
@Self
private SlingHttpServletRequest request;
/**
* The link manager.
*/
@Self
private LinkManager linkManager;
/**
* The current page.
*/
@ScriptVariable
private Page currentPage;
/**
* The current style.
*/
@ScriptVariable
private Style currentStyle;
/**
* The language manager service.
*/
@OSGiService
private LanguageManager languageManager;
/**
* The relationship manager service.
*/
@OSGiService
private LiveRelationshipManager relationshipManager;
/**
* The accessibility label.
*/
@nullable
private String accessibilityLabel;
/**
* Number indicating how many levels below the navigation root the navigation should start.
*/
private int structureStart;
/**
* Number indicating how many levels below the navigation root should be included in the results.
* Use "-1" for no limit.
*/
private int structureDepth;
/**
* The root page from which to build the navigation.
*/
private Page navigationRootPage;
/**
* Placeholder for the list of results.
*/
private List<NavigationItem> items;
/**
* Initialize the model.
*/
@PostConstruct
private void initModel() {
ValueMap properties = this.resource.getValueMap();
structureDepth = properties.get(PN_STRUCTURE_DEPTH, currentStyle.get(PN_STRUCTURE_DEPTH, -1));
boolean collectAllPages = properties.get(PN_COLLECT_ALL_PAGES, currentStyle.get(PN_COLLECT_ALL_PAGES, true));
if (collectAllPages) {
structureDepth = -1;
}
if (currentStyle.containsKey(PN_STRUCTURE_START) || properties.containsKey(PN_STRUCTURE_START)) {
//workaround to maintain the content of Navigation component of users in case they update to the current i.e. the `structureStart` version.
structureStart = properties.get(PN_STRUCTURE_START, currentStyle.get(PN_STRUCTURE_START, 1));
} else {
boolean skipNavigationRoot = properties.get(PN_SKIP_NAVIGATION_ROOT, currentStyle.get(PN_SKIP_NAVIGATION_ROOT, true));
if (skipNavigationRoot) {
structureStart = 1;
} else {
structureStart = 0;
}
}
}
/**
* Get the effective navigation root page.
*
* @Return The effective navigation root page.
*/
private Page getNavigationRoot() {
if (this.navigationRootPage == null) {
String navigationRootPath = Optional.ofNullable(this.resource.getValueMap().get(PN_NAVIGATION_ROOT, String.class))
.orElseGet(() -> currentStyle.get(PN_NAVIGATION_ROOT, String.class));
this.navigationRootPage = LocalizationUtils.getLocalPage(navigationRootPath,
this.currentPage,
this.request.getResourceResolver(),
this.languageManager,
this.relationshipManager)
.orElseGet(() -> currentPage.getPageManager().getPage(navigationRootPath));
}
return this.navigationRootPage;
}
@Override
public List<NavigationItem> getItems() {
if (this.items == null) {
this.items = Optional.ofNullable(this.getNavigationRoot())
.map(navigationRoot -> getRootItems(navigationRoot, structureStart))
.orElseGet(Stream::empty)
.map(item -> this.createNavigationItem(item, getItems(item)))
.collect(Collectors.toList());
}
return Collections.unmodifiableList(items);
}
protected NavigationItem newNavigationItem(Page page, boolean active, boolean current, @notnull LinkManager linkManager, int level,
List<NavigationItem> children, String parentId, Component component) {
return new NavigationItemImpl(page, active, current, linkManager, level, children, parentId, component);
}
@Override
@nullable
public String getAccessibilityLabel() {
if (this.accessibilityLabel == null) {
this.accessibilityLabel = this.resource.getValueMap().get(PN_ACCESSIBILITY_LABEL, String.class);
}
return this.accessibilityLabel;
}
@notnull
@Override
public String getExportedType() {
return this.resource.getResourceType();
}
/**
* Builds the navigation tree for a {@code navigationRoot} page.
*
* @Param subtreeRoot The page for which to generate the sub-tree.
* @Return the list of collected navigation trees
*/
private List<NavigationItem> getItems(@NotNull final Page subtreeRoot) {
if (this.structureDepth < 0 || subtreeRoot.getDepth() - this.getNavigationRoot().getDepth() < this.structureDepth) {
Iterator<Page> childIterator = subtreeRoot.listChildren(new PageFilter());
return StreamSupport.stream(((Iterable<Page>) () -> childIterator).spliterator(), false)
.map(item -> this.createNavigationItem(item, getItems(item)))
.collect(Collectors.toList());
}
return Collections.emptyList();
}
/**
* Gets a stream of the top level of pages in the navigation.
*
* @Param navigationRoot The navigation root page.
* @Param structureStart The number of levels under the root page to begin collecting pages.
* @Return Stream of all descendant pages of navigationRoot that are exactly structureStart levels deeper.
*/
private Stream<Page> getRootItems(@NotNull final Page navigationRoot, final int structureStart) {
if (structureStart < 1) {
return Stream.of(navigationRoot);
}
Iterator<Page> childIterator = navigationRoot.listChildren(new PageFilter());
return StreamSupport.stream(((Iterable<Page>) () -> childIterator).spliterator(), false)
.flatMap(child -> getRootItems(child, structureStart - 1));
}
/**
* Create a navigation item for the given page/children.
*
* @Param page The page for which to create a navigation item.
* @Param children The child navigation items.
* @Return The newly created navigation item.
*/
private NavigationItem createNavigationItem(@NotNull final Page page, @notnull final List<NavigationItem> children) {
int level = page.getDepth() - (this.getNavigationRoot().getDepth() + structureStart);
boolean current = checkCurrent(page);
boolean selected = checkSelected(page, current);
return newNavigationItem(page, selected, current, linkManager, level, children, getId(), component);
}
/**
* Checks if the specified page is selected.
* A page is selected if it is either:
* <ul>
* <li>The current page; or,</li>
* <li>A page that redirects to the current page; or,</li>
* <li>The current page is a child of the specified page</li>
* </ul>
*
* @Param page The page to check.
* @Return True if the page is selected, false if not.
*/
private boolean checkSelected(@NotNull final Page page, boolean current) {
return current
|| this.currentPage.getPath().startsWith(page.getPath() + "/");
}
private boolean checkCurrent(@NotNull final Page page) {
return this.currentPage.equals(page)
|| currentPageIsRedirectTarget(page);
}
/**
* Checks if the specified page redirects to the current page.
*
* @Param page The page to check.
* @Return True if the specified page redirects to the current page.
*/
private boolean currentPageIsRedirectTarget(@NotNull final Page page) {
return currentPage.equals(Utils.resolveRedirects(page).getLeft());
}
}
Views
Replies
Total Likes
You can readily use all the existing code by using Delegation https://experienceleague.adobe.com/docs/experience-manager-core-components/using/developing/customiz...
You just need to use @Via annotation. Following would not be required.
Views
Replies
Total Likes
I don't see a problem with your code... make sure you are using the correct AEM Cloud SDK (if you are on AEMaaCS), and if you are using classic AEM, make sure you have the correct service pack and/or the AEM WCM Core Components installed as expected.
This code works fine for me.
<nav data-sly-use.navigation="com.adobe.cq.wcm.core.components.models.Navigation"
data-sly-use.template="core/wcm/components/commons/v1/templates.html"
data-sly-use.groupTemplate="group.html"
data-sly-call="${groupTemplate.group @ items=navigation.items}"
data-sly-test.hasContent="${navigation.items.size > 0}"
id="${navigation.id}"
class="cmp-navigation"
itemscope itemtype="http://schema.org/SiteNavigationElement"
data-cmp-data-layer="${navigation.data.json}"
aria-label="${navigation.accessibilityLabel}">
</nav>
<sly data-sly-call="${template.placeholder @ isEmpty=!hasContent, classAppend='cmp-navigation'}"></sly>
Views
Replies
Total Likes
Views
Likes
Replies