April 25, 2020
Estimated Post Reading Time ~

Infinite Scroll using JSCroll



This post shows how to implement an infinite scroll in AEM classic and touch UI using a jQuery Plugin jScroll. For more information about the jQuery Plugin jScroll please visit http://jscroll.com


PRE-REQUISITES
Create an initial Maven Project with the basic archetype. If you haven’t set up Maven yet or don’t know how to create an archetype, follow the steps under the “Setup Maven” section of this guide:
https://helpx.adobe.com/experience-manager/using/creating-sightly-component.html


Back-end
First, we have to create a service that extends from WCMUse. Using this service, we will get all the children that contain images and display all the images within the path of a selected page. In order to empower this, you are going to create two different solutions only by changing only one line of code. The first solution will give you only the first level of children pages (not the children of children) and the other solution will return you all the children pages of the path given.

This service has a method to obtain the first pages to be shown, starting in the actual page and another method to get the next pages for the infinite scroll.
This method returns the page of the actual paginated index, as well as the pages to show at that time, but not all existing pages.
This is important because it improves the performance since the page is loaded on demand.

The method used to obtain the pages searches the children's pages from the start page of the path used using the query builder. Then the result of the query is processed and it builds a list of the pages that have images.

The method would look like this:


public  List getPages(){
        //getting the property value which contains the main path, from the resource node
        String path = getPropertyValue();
        
        Map<String, String> predicates = new HashMap<String,String>();
        
        predicates.put("path", path);
        predicates.put("type", TYPE);
       //uncomment the line below in order to get only the first level of child pages.
      //predicates.put("path.flat", "true");
        predicates.put("p.limit", BASE_LIMIT);//limita la cantidad de resultados
        predicates.put("1_property", "@jcr:content/image");//Only pages with Images
        predicates.put("p.offset", this.startPage.toString());
        
        PredicateGroup predGroup = PredicateGroup.create(predicates);
        ResourceResolver resolver = this.getResourceResolver();
        
        session = resolver.adaptTo(Session.class);
        builder = resolver.adaptTo(QueryBuilder.class);
        query = builder.createQuery(predGroup, session);
   
        return getListPageInfo();
    }

Let’s explain this code a bit:
List<PageInfo>: PageInfo is a POJO with these attributes: private String path, private String imgPath, private String imgExtension, getters, and setters.
TYPE: is a constant private final String TYPE = “cq:Page”, in order to filter by Pages.
BASE_LIMIT: is constant private final String BASE_LIMIT = “5”
p.limit: the number of items returned.
Path.flat: allow us to filter by only the first step of child pages.
p.offset: Mostly used in pagination, is the offset for paging.

As you can see this method calls another two methods, one named getPropertyValue which gets the property that contains the main path from the resource node, and the other one named getListPageInfo(), which returns a list of PageInfo charged with the image and the path.

Here is the implementation of both:


private String getPropertyValue() {
 Resource parResource = getCurrentPage().getContentResource(PARENT_NODE);
 Resource rootResource = parResource.getChild(CHILD_NODE);
 return (String) rootResource.getValueMap().get(PROPERTY_NAME);
}

Obs:
PROPERTY_NAME is the name of the property called “name” of the dialog which has a path field. And the other method:


private List getListPageInfo() {
 List listPage = new ArrayList();
 try {
  if (query.getResult() != null) {
   for (Hit hit: query.getResult().getHits()) {

    PageInfo pageInfo = new PageInfo();

    Page page = this.getPageManager().getPage(hit.getPath());

    Resource r = page.getContentResource("image");
    if (r != null) {

     Image image = new Image(r);
     pageInfo.setImgPath((String) image.getFileReference());
     pageInfo.setImgExtension((String) image.getExtension());
    }

    pageInfo.setPath(hit.getPath());

    listPage.add(pageInfo);

   }

  }
 } catch (RepositoryException e) {
  e.printStackTrace();
 }
 return listPage;
}

Finally we have the startPage method which allows us to know the position of the pagination:

public int getStartPage() {
 return startPage + Integer.parseInt(BASE_LIMIT);
}
Front-end
Let’s now create the clientlibs. This folder should have a clientLibraryFolder type and must have a categories type to include in the component:



Its properties:



In this folder we include the js files for the infinite scroll, in this case we also include the jquery.jscroll.js, but it could be jquery.jscroll.min.js instead. If you take a look to the picture above, we also have to create an extra file called scripts.js inside the clientlibs folder which contains the following code


$(document).ready(function () {
    $('.scroll').jscroll({
            contentSelector: '.mylist'
    });
})

We should be initializing the jscroll for all the content inside the div that contains the class “mylist”.

We are now able to write the Sightly code in the HTML component to use infinite scroll:


Let's explain this code
data-sly-use.data: The first div includes the bundle which has the logic for the pagination.
data-sly-list: It allows us to have a list loaded with the method getPages inside the bundle.
data-sly-test: Only shows the HTML inside that div section if the conditions are both true.

Inside the hyperlink, we are getting the path of the current node, in order to send the server the last position of the pagination by the method named startPage.

In this code, you can see how the infinite scroll calls the methods. When scrolling the page, the method startPage is called and jScroll automatically loads content into the page via AJAX.

To make this component more visible to the user, we add some style so now, we have to create a style.css file inside the clientlibs folder.


.scroll {
    border: 1px solid #aaa;
    padding: 5px 10px;
    height: 500px;
    overflow-y: scroll;
    margin: 20px 0;
    background: #ffc;
}

Finally, we have to create the dialog in order to obtain the path where the images are. In this case, we create one dialog for the classic version and another dialog for touch UI.

Here is the structure:


And the most important properties:
For Touch UI:


For classic:


Here are some result screenshots
Touch UI solution:


Classic solution:


By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.