Pagination in LoopBack 3

August 20, 2018 ~ 4 min read

Pagination in LoopBack 3


This article originally appeared on Medium.

When developing an application with a LoopBack backend it usually won’t take long until you will need some kind of pagination in your frontend to make long lists of countless items more user-friendly to navigate.

Thankfully LoopBack has a skip filter and a limit filter which allows us to implement pagination with just using some url parameters. Your first request to fetch the list would contain

?filter={“skip”:0,”limit”:10}

the next request

?filter={“skip”:10,”limit”:10}

and so on. This is quite useful!

However whether you are building a classic pagination with pages, a load more button or even some kind of infinite scrolling you might want to know exactly how many pages there are or how many items there are left to fetch. In this post I will discuss two options to solve this issue: the X-Total-Count header and the loopback-paginator mixin.


Did you know I built Monitornator?
Peace of Mind-as-a-Service.
We keep an eye on your servers so you don't have to.

The X-Total-Count header

As the headline might suggest one solution would be to add a header to your response that tells you, how much items there are in total. This can easily be done with the following boot script you just have to place into the server/boot directory.

/**
 * Sets headers used for client-side pagination
 */
module.exports = function (app) {
  var remotes = app.remotes();

  // Set X-Total-Count for all find requests
  remotes.after('*.find', function (ctx, next) {
    var filter;
    if (ctx.args && ctx.args.filter) {
      try {
        filter = JSON.parse(ctx.args.filter).where;
      } catch(e) {
        filter = ctx.args.filter.where;
      }
    }

    if (!ctx.res._headerSent) {
      this.count(filter, function (err, count) {
        ctx.res.set('X-Total-Count', count);
        next();
      });
    } else {
      next();
    }
  });
};

This will automatically intercept all calls for item lists (find) and add the X-Total-Count header to the response. This also takes filters into account. So if you applied a where filter to your request only items that fit your filter will be counted.

In your frontend you can use that total count to calculate the number of available pages for example or hide the load more button if no more items are available.

The loopback-paginator

The second option is to use the loopback-paginator mixin. (Full disclosure: I’m the author of this mixin which I wrote to have an in my opinion more elegant solution to the pagination problem.) After installing and applying the mixin to your models (check the readme to see all available options), the response body of your GET /api/items requests will look slightly different:

{
  "data": [
    {
      "title": "Item 1",
      "description": "Cool first item.",
      "id": "c5075168-abe0-41c6-8052-e07745eade48"
    },
    {
      "title": "Item 2",
      "description": "Cool second item.",
      "id": "0cad55df-c59d-4195-bb4f-7a252bd4bbe8",
    }

    ...

  ],
  "meta": {
    "totalItemCount": 95, // total number of items
    "totalPageCount": 10, // total number of all pages
    "itemsPerPage": 10,   // numberof items per page
    "currentPage": 3,     // the current page
    "nextPage": 4,        // the next page, only present if there is another page
    "previousPage": 2     // the previous page, only present if currentPage != 1
  }
}

Instead of an array with all your items the body will contain data and meta. Data contains the array of items as you are used to and meta contains some helpful information to implement pagination. You will see the total number of items, the total number of available pages, the number of items per page as well as the current, previous and next page (if available). This solution also takes all your applied filters into account.

I just started working on the paginator last week, but I have some more features in mind and updates will come soon.

So which solution you want to use is totally up to you. They will both optimise the user experience of your application.