Core Component Breadcrumb Title

juliat18240654

15-06-2020

Is it possible to override the Breadcrumb or Page List component to use a different page title than the Navigation Title? 

 

I have a requirement where I need to use a shorter title in the Breadcrumb component than in the Page List Component, however, both are using the Navigation Title. If there is a way that I can use one title type for one component and another for the other component, that would be ideal.

 

I'm a relative beginner with Java and don't entirely understand how the Delegation Pattern for Sling Models (https://github.com/adobe/aem-core-wcm-components/wiki/Delegation-Pattern-for-Sling-Models) could tie into what I'm trying to do here, but if there is a tutorial or some information that might help guide a solution, I would appreciate the insight.

Accepted Solutions (1)

Accepted Solutions (1)

Theo_Pendle

MVP

15-06-2020

Hi @juliat18240654,

It depends what you mean by "one title type for one component and another for the other component", because there are many title types. However, let's have a look at why the Navigation Title is used.

The breadcrumb model returns a list of NavigationItems (the interface). These are in fact instances of BreadcrumbItemImpl (the class). They in turn fetch the title property (which is used in the rednering HTL script using the following algorithm:

@Override
    public String getTitle() {
        String title = page.getNavigationTitle();
        if (title == null) {
            title = page.getPageTitle();
        }
        if (title == null) {
            title = page.getTitle();
        }
        if (title == null) {
            title = page.getName();
        }
        return title;
    }

 So all you need to do is override this behavior slightly. Let's say for example that you want to use the Page Title and not the Navigation Title in a breadcrumb, you should create the following item:

import com.adobe.cq.wcm.core.components.models.NavigationItem;
import lombok.Getter;
import lombok.experimental.Delegate;

public class CustomNavigationItem implements NavigationItem {

    // Here we delegate everything to the original item, except the getTitle method (see interface below)
    @Delegate(excludes = DelegationExclusion.class)
    private final NavigationItem delegate;

    // Rather than getting a title from a page using an the algorithm I showed above, this item will simply return
    // whatever String was given to it in its constructor
    @Getter
    private final String title;

    public CustomNavigationItem(final NavigationItem item, final String title) {
        this.delegate = item;
        this.title = title;
    }

    private interface DelegationExclusion {
        String getTitle();
    }
}

Then, return these CustomNavigationItems rather than the default items using this model:

import com.adobe.cq.wcm.core.components.models.Breadcrumb;
import com.adobe.cq.wcm.core.components.models.NavigationItem;
import com.day.cq.wcm.api.PageManager;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.Via;
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 java.util.Collection;
import java.util.stream.Collectors;

@Model(
        adaptables = {Resource.class, SlingHttpServletRequest.class},
        adapters = Breadcrumb.class,
        resourceType = "demo/components/content/breadcrumb",
        defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL
)
public class CustomBreadcrumb implements Breadcrumb {

    @Self
    @Via(type = ResourceSuperType.class)
    private Breadcrumb delegate;

    @ScriptVariable
    private PageManager pageManager;

    @Override
    public Collection<NavigationItem> getItems() {

        // For each item, create an instance of our custom item
        return delegate.getItems().stream().map(item -> {

            // Set the title to be the page title
            final String pageTitle = pageManager.getPage(item.getPath()).getPageTitle();
            return new CustomNavigationItem(item, pageTitle);
            
        }).collect(Collectors.toList());
    }

    @Override
    public String getExportedType() {
        return delegate.getExportedType();
    }
}

Here is the result! The page properties:

Selection_168.png

Ans as you can see, the page title is used, not the navigation title! Sorry, didn't have time for CSS 😛 

Selection_169.png

I've been generous with comments on the parts that are relative to your use-case. If you want a step-by-step tutorial to explain exactly how it all works, I wrote one recently here: https://levelup.gitconnected.com/aem-extend-core-component-models-using-resource-type-association-an... 🙂

Answers (0)