3d cartoon hands holding a phone

Unlock full course by purchasing a membership

Lesson 6

Adding Pagination with Infinite Scroll


Adding Pagination with Infinite Scroll

At the moment, we just get a bunch of GIFs, display them, and that’s it. We are going to improve this a little now. Instead of just dumping everything we get from a single request, we are going to only display a set amount of GIFs per “page”. When the user scrolls to the bottom of the page, we will automatically load in more GIFs if they are available.

To do this, we will need to make some changes to our gifsLoaded$ stream, and we are also going to make use of the third party ngx-infinite-scroll library to help us trigger a load when the user scrolls to the bottom of the page.

Adding Support for Pagination

Before we can trigger a new page with our infinite scroll mechanism, we need a way to actually trigger and load new pages.

We will do this by extending our RedditService with a pagination$ source. We are going to have to make some other changes as well.

When we are loading data from the Reddit API we do not just load specific pages of data, e.g:


We will instead request data after the name a specific post, like this:


We will need to keep track of the name of whatever the last known gif we have seen is — as in the gif at the very end of our list. We will then use the name of that gif as the after when we are trying to load a new page.

This means we are going to need to make some changes to our state. In fact, there are other things we will eventually want to store in the state too, so let’s handle all of that now.

Update the GifsState to reflect the following:

export interface GifsState {
  gifs: Gif[];
  error: string | null;
  loading: boolean;
  lastKnownGif: string | null;

Update the initial state to the following:

  private state = signal<GifsState>({
    gifs: [],
    error: null,
    loading: true,
    lastKnownGif: null,

Let’s also add some more selectors to select our new state.

Update the selectors to match the following:

  // selectors
  gifs = computed(() => this.state().gifs);
  error = computed(() => this.state().error);
  loading = computed(() => this.state().loading);
  lastKnownGif = computed(() => this.state().lastKnownGif);

The next thing we will need is a new source that we can next when we want to trigger a new page loading — we will call this pagination$. We will also need to update our gifsLoaded$ source to react to the pagination$ source emitting, and whenever it does it should trigger a new request to fetch data from Reddit.

For now, we will just repeat the same request rather than worrying about tracking the lastKnownGif. Just to get the basic set up working.

This is by no means an easy task, but see if you can figure out how to add the pagination$ source and cause the gifsLoaded$ to emit with the data from an HTTP request to the Reddit API every time that we call next on pagination$.

Update the sources to reflect the following:

  pagination$ = new Subject<void>();
  private gifsLoaded$ = this.pagination$.pipe(
    concatMap(() => this.fetchFromReddit('gifs'))

Now rather than gifsLoaded$ immediately making a single request to Reddit, it will make one every time that pagination$ emits. If we used switchMap here it would cause the currently executing request to be cancelled and we would switch to the new request every time that pagination$ emits. This is why we use concatMap instead. If the user were to trigger two page loads in quick succession, we wouldn’t want the first request to be cancelled. This way, the concatMap would wait for the first request to finish, and then it would start the second request.

The problem here though is that now no gifs will load until we manually trigger the pagination source. That’s a bit annoying and doesn’t feel very reactive/declarative.


Thanks for checking out the preview of this lesson!

You do not have the appropriate membership to view the full lesson. If you would like full access to this module you can view membership options (or log in if you are already have an appropriate membership).