April 7, 2020
Estimated Post Reading Time ~

Sightly Pagination Component using Sling Model and JavaScript Use API in AEM 6.1

I will be demonstrating a Sightly Pagination Component in AEM 6.1, complete code and sample authored pages are available on our GitHub Repository

To any AEM Developer, I would highly recommend you to go through this article as this pagination component works together with some of the important concepts of AEM like Query Builder, Sling Model, JavaScript Use API and Sightly. In terms of functionality of this component its very similar to what we have in our AEM Community.

Here’s the overview of our pagination component:-
Component will accept two inputs from author, one being title of component and other being path from where it has to read pages. Let’s say the path you have give is /content/geometrixx-media/en now it will select all pages having node type as cq:Page . Type of query you want to perform can be easily changed. Now based on the search result it gets, paginations will be created on page. It uses selector based approach, once you click next page or any number you can notice selector will be added on URL.

Operations performed by each modules:-
1. Sling Model: It adapts the pages as SlingHttprequest thus we can easily retrieve selector parameter.
2. Query Builder: Based on the selector received on step it queries the JCR.
3. JavaScript Use API: With the help of number of results it create pagination links.
4. Sightly: As usual its used as View to render everything to user.

Let’s get started with authoring our component…

1. Use the component name “Sightly Pagination” and drag and drop it onto page


2. Author the two required fields. One is the title displayed on top of page and other being the root page.


3. Once you have submitted that component output can be seen on page

First section


Mid Section


Invalid Selector


Time to take a look at code…

When dialog is submitted request goes to sling model class which adapts itself as SlingHttpServletRequest.class

package com.sightlypagination.core.models;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;
import javax.jcr.Session;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.models.annotations.Default;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.Source;
import org.apache.sling.settings.SlingSettingsService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.day.durbo.DurboInput.Node;

@Model(adaptables = SlingHttpServletRequest.class)
public class HelloWorldModel {
 private final Logger logger = LoggerFactory.getLogger(getClass());

 @Inject
 SlingHttpServletRequest request;

 private String message;

 private String sel = null;

 private List < SimplePage > pageList = null;

 SimplePage page = null;

 private List < String > file;

 @Inject
 @Source("osgi-services")
 PaginationInterface service;

 @PostConstruct
 protected void init() {
  try {
   pageList = new ArrayList < SimplePage > ();
   Session session = request.getResource().getResourceResolver()
    .adaptTo(Session.class);
   ValueMap node = request.getResource().getValueMap();
   String path = node.get("text", String.class);

   if (request != null) {
    List < String > selectors = Arrays.asList(request
     .getRequestPathInfo().getSelectors());
    if (selectors.size() > 0)
     this.sel = selectors.get(0);
    else
     this.sel = "0";

    this.file = service.getPaginationData(path, String.valueOf(5),
     this.sel);
    this.message = service.getMatches();

    for (String s: this.file) {
     page = new SimplePage();
     String title = session.getNode(s + "/jcr:content")
      .getProperty("jcr:title").getString();
     page.setPath(s);
     page.setTitle(title);

     pageList.add(page);

    }

   }
  } catch (Exception e) {
   logger.info("Exception:" + e.getMessage());
  }
 }

 public List < String > getFiles() {

  return this.file;
 }

 public String getMessage() {
  return this.message;
 }

 public List < SimplePage > getPage() {
  return this.pageList;
 }

}


Our sling model injects OSGI Service and @PostConstruct method gets called once all the injections are done.

Now this method is very important from implementation point of view. Its checks for the selector which is further passed to our OSGI service which uses Query Builder to get the data. Returned data is put in list with the help of class SimplePage and returned to Sightly File. sightly-pagination.html files displays all the data on the page.

The pagination you are seeing on the page are shown with the help of our sightly-pagination.js which uses JavaScript use API.

"use strict";

use(function() {
 try {

  // setting the limit
  var limit = 5;

  var m = parseInt(this.matches);
  var offset, p = "",
   next, pages;
  var selectors = new Array();

  var pages = new Array();
  selectors = request.getRequestPathInfo().getSelectors();

  // Getting Selector
  if (selectors.length != 0)
   var sel = parseInt(selectors[0]);
  else
   var sel = 0;

  var maxSel = parseInt(m / 5 + 1) - 1;
  maxSel = Math.floor(maxSel - 1);
  if (maxSel == -1)
   maxSel = 0;
  log.info("Max Selector " + maxSel);

  // Previous Link
  if (sel != 0 && sel < m / 5 + 1) {
   p = parseInt(sel) - 1;
  }

  // Next link
  if ((sel + 1) * 5 > m) {
   next = "";
  } else {
   next = parseInt(sel) + 1;
  }

  // Need to find 5 links including adjacent links and current one
  var fcount = 0;
  var bcount = 0;
  var flimit = 2;
  var blimit = 2;

  if (maxSel - sel >= 2) {
   var blimit = 2;
  } else {
   flimit = parseInt(flimit) +
    (parseInt(blimit) - (parseInt(maxSel) - parseInt(sel)));
   log.info(flimit);
   blimit = maxSel - sel;
  }

  if (parseInt(sel) - 0 < 2) {
   blimit = blimit + flimit - parseInt(sel) - 0;
  }

  // Front
  for (i = sel - 1; i >= 0; i--) {
   if (fcount != flimit) {
    log.info(fcount);
    pages[fcount] = i;
    fcount++;
   }
  }

  for (i = parseInt(sel) + 1; i <= maxSel; i++) {
   log.info("i=" + i);
   if (bcount != blimit) {
    pages[bcount + fcount] = i;
    bcount++;
   }
  }

  log.info(pages.length)
  pages[pages.length] = parseInt(sel);

  var list = [];
  for (var n = 0; n < pages.length; n++) {

   var x = parseInt(pages[n]);
   list[n] = x;
   // }
  }

  list.sort(function(a, b) {
   return a - b
  });

  for (var n = 0; n < list.length; n++) {
   log.info(list[n])
   log.info(isNaN(list[n]));
  }

  var pageList = new Array();
  for (var n = 0; n < list.length; n++) {

   var link = [];
   var x = parseInt(list[n]) + 1;
   link[0] = list[n].toString();
   link[1] = x.toString();

   list[n] = link;

  }

  // Check for invalid pagination
  var valid = true;
  if (parseInt(sel) > parseInt(maxSel))
   valid = false;

  // Removing single element is it has only one page
  if (list.length == 1)
   list.pop();

  return {
   previous: p.toString(),
   next: next.toString(),
   pages: list,
   check: valid

  };

 } catch (e) {
  log.info(e);
 }
});

(Refer to our previous article if you are new to JavaScript Use API )

Above shown code creates sectional pagination and “Next” and “Previous” links.



By aem4beginner

No comments:

Post a Comment

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