Expand my Community achievements bar.

SOLVED

How to get child pages of a component using sling model?

Avatar

Level 1

A developer is creating a custom component on the page and needs to list all the child pages of the root page. How to do that and what is the correct way to do that?

1 Accepted Solution

Avatar

Correct answer by
Level 4

A good sample! except that it's better always to use try-with-resources as the resource resolver is of Closeable interface, and the ArrayList should be used instead of the default LinkedList only in limited cases when you need to update the list after filling it.

In addition from me, if you use those pages to build a list of links, you should check for other properties, for example, if the page is a redirect one, you should display the target page instead of found one, and also if you need to traverse no only first children, but a whole tree, I use this approach:

// public final class StreamUtils {

  public static Stream<Page> descendants(@Nullable final Page rootPage) {
    return Optional.ofNullable(rootPage).map(rootPage -> 
        Stream.concat(Stream.of(rootPage),
          StreamSupport.stream(Spliterators.spliteratorUnknownSize(rootPage.listChildren(),
              Spliterator.ORDERED), false)
            .flatMap(StreamUtils::descendants)))
      .orElse(Stream.empty());
  }

I have inlined some utility functions that I use to get it shorter, I hope I didn't brake it as I did it right here not in IDE  And then I use this function as:

final List<Page> allDescendantPages = StreamUtils.descendants(rootPage).collect(Collectors.toList());

 

View solution in original post

2 Replies

Avatar

Employee

Hi @nats ,

 

You can create a simple Sling Model class for your component to get the root page and access all the child pages of that root page. 
Sample code for java model class : 

package com.example.models;

import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.sling.api.resource.Resource;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageManager;

@Component(service = ChildPagesModel.class)
public class ChildPagesModel {

    @Reference
    private ResourceResolverFactory resourceResolverFactory;

    private List<Page> childPages;

    @PostConstruct
    protected void init() {
        childPages = new ArrayList<>();
        String rootPagePath = "/content/your-site-root"; // Replace this with the actual path to your root page

        ResourceResolver resourceResolver = null;
        try {
            // Get the ResourceResolver using ResourceResolverFactory
            resourceResolver = resourceResolverFactory.getServiceResourceResolver(null);
            PageManager pageManager = resourceResolver.adaptTo(PageManager.class);

            if (pageManager != null) {
                Page rootPage = pageManager.getPage(rootPagePath);
                if (rootPage != null) {
                    Iterator<Page> childIterator = rootPage.listChildren();
                    while (childIterator.hasNext()) {
                        Page childPage = childIterator.next();
                        childPages.add(childPage);
                    }
                }
            }
        } catch (Exception e) {
            // Handle exceptions
            e.printStackTrace();
        } finally {
            // Always close the ResourceResolver when done
            if (resourceResolver != null) {
                resourceResolver.close();
            }
        }
    }

    public List<Page> getChildPages() {
        return childPages;
    }
}

You can then use this model in your HTL code by doing 

<div data-sly-use.childPages="com.example.models.ChildPagesModel"> <ul> <li data-sly-repeat.child="${childPages}"> <a href="${child.path}.html">${child.title}</a> </li> </ul> </div>

 

Hope it helps!

Thanks,
Ayush

Avatar

Correct answer by
Level 4

A good sample! except that it's better always to use try-with-resources as the resource resolver is of Closeable interface, and the ArrayList should be used instead of the default LinkedList only in limited cases when you need to update the list after filling it.

In addition from me, if you use those pages to build a list of links, you should check for other properties, for example, if the page is a redirect one, you should display the target page instead of found one, and also if you need to traverse no only first children, but a whole tree, I use this approach:

// public final class StreamUtils {

  public static Stream<Page> descendants(@Nullable final Page rootPage) {
    return Optional.ofNullable(rootPage).map(rootPage -> 
        Stream.concat(Stream.of(rootPage),
          StreamSupport.stream(Spliterators.spliteratorUnknownSize(rootPage.listChildren(),
              Spliterator.ORDERED), false)
            .flatMap(StreamUtils::descendants)))
      .orElse(Stream.empty());
  }

I have inlined some utility functions that I use to get it shorter, I hope I didn't brake it as I did it right here not in IDE  And then I use this function as:

final List<Page> allDescendantPages = StreamUtils.descendants(rootPage).collect(Collectors.toList());