Step-by-Step Guide: Angular Infinite Scroll With Responsive viewport

1 minute read

I recently implemented Infinite Scrolling for a large amount data stored in firestore, with response layout using Angular 9. So this post is just a small replica of the same

Pre-requisite

  • A running angular 9 application

Setup

  1. Install Angular CDK

npm i @angular/cdk

Angular CDK consists of many modules, but for this post we will focus on Scrolling and Layout modules

  1. Create a basic virtual scroll

Add ScrollingModule

app.module.ts

// other imports here
import {ScrollingModule} from '@angular/cdk/scrolling';

@NgModule({
  imports: [ 
    BrowserModule,
    FormsModule,
    ScrollingModule
  ],
  providers: [
    AngularFirestore,
    AngularFirestoreModule
  ],
  declarations: [ AppComponent, HelloComponent ],
  bootstrap:    [ AppComponent ]
})

// remaining code here

app.component.html

<cdk-virtual-scroll-viewport itemSize="140" class="card-container">
  <div *cdkVirtualFor="let item of items">
       
  </div>
</cdk-virtual-scroll-viewport>

Define variable items app.component.ts

items: Array<string> = ["one", "two", "three"];
  1. Flex items

Currently virtual scroll displays one item in a row, what if we want multi elements in stacked in a row So there is no way to do it directly from CSS by applying flex property to the container.To solve this, the items array is divided into smaller chunks of predefined size

app.component.ts

tail = (a) => a[a.length - 1];

chunkReducerForSize = (chunkSize = 2) => (result, item) => {
    const lastElm = this.tail(result);
    if (lastElm.length === chunkSize) {
      result.push([item]);
    } else {
      lastElm.push(item);
    }
    return result;
  };

toChunks = (arr, chunkSize = 5) => {
    return arr.reduce(this.chunkReducerForSize(chunkSize), [[]]);
 };
console.log(toChunks(items,2));

[Array[2], Array[1]]
0: Array[2]
  0: "one"
  1: "two"
1: Array[1]
  0: "three"
  1. Responsive Layout

Now, since we want to change the number of elements in a single row depending on screen size, we will use LayoutModule from @angular/cdk and change the chunkSize accordingly

Add LayoutModule

app.module.ts

import {LayoutModule} from '@angular/cdk/layout';

We use a BehaviorSubject() for chunkSize so that the chunks are generated whenever the chunkSize changes. Default chunkSize is defined as 2.

chunkSize = new BehaviorSubject(2);

Now we subscribe to predefined breakpoints, but custom breakpoints can also be defined

The built-in breakpoints are based on Material Design Specification

app.component.ts

import { BreakpointObserver, Breakpoints } from "@angular/cdk/layout";
// other imports

constructor(private breakpoint$: BreakpointObserver){
breakpoint$.observe([
      Breakpoints.XSmall,
      Breakpoints.Small,
      Breakpoints.Medium
    ]).subscribe(result => {
      if (result.breakpoints[Breakpoints.XSmall]) {
        this.chunkSize.next(2);
      }
      else if (result.breakpoints[Breakpoints.Small]) {
        this.chunkSize.next(4);
      }
      else if (result.breakpoints[Breakpoints.Medium]) {
        this.chunkSize.next(6);
      }
      else {
        this.chunkSize.next(8);
      }
    });
}

Demo

Stackblitz Demo

Updated:

Leave a comment