DEV Community

Hassam Ali
Hassam Ali

Posted on

Angular CDK Virtual Scroll

What is Virtual Scrolling?

Modern web application are complex. They have a lot of moving parts, complexity and often times they have to deal with huge amount of data.

Consider that you have application in which you have to display a list of users, a very common use case.

As the number of items in the list increase so does number of elements in DOM resulting in more memory and cpu usage.
We can reduce memory and cpu consumption by rendering only limited set of all the items, we can determine this limited set by looking at the height of container, scroll position and height of individual item and then perform some calculations which tell us which items from the list should rendered in DOM and as soon user scroll we again perform this calculation, remove previously rendered items and render new items according to calculation. All of this sounds very complex and it is, but the good news is that Angular Material CDK Virtual Scroll does this all for you and then some more. From now on I will be referring Angular Material CDK Virtual Scroll as Virtual Scroll

So let's get started!

Prerequisites

Before we begin we need a sample application with list of data so we can play with it and later on add angular virtual scroll to it. I have created a small example
This example is built on using Angular version 8. It uses fake to generate fake data, add it to array and uses *ngFor to render item of array as DOM elements in template.

Installation

Installing Material CDK is pretty straight forward. If you are following along: In the stackblitz demo click on dependencies, it is just beneath window where project file are listed see screen shot below, type @angular/cdk and hit enter this will install material cdk. If you want to install it inside your angular cli project simply type npm i --save @angular/cdk

Installing CDK

Once you have installed CDK, we are ready to move towards next step: using it!

Usage

Before we can begin using the Virtual Scroll we need to import the module for it. Let's import it. Open your app.module.ts add this line after the last import

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

This will import the ScrollingModule, now we need to tell our app.module.ts to import contents of this module. For this inside the imports array add ScrollingModule your app.module.ts will look like this

 import  {  NgModule  }  from  '@angular/core';
import  {  BrowserModule  }  from  '@angular/platform-browser';
import  {  FormsModule  }  from  '@angular/forms';
import  {  AppComponent  }  from  './app.component';
import  {  ScrollingModule  }  from  '@angular/cdk/scrolling';

@NgModule({
imports:  [  BrowserModule,  FormsModule,  ScrollingModule  ],
declarations:  [  AppComponent  ],
bootstrap:  [  AppComponent  ]
})
export  class  AppModule  {  }
Enter fullscreen mode Exit fullscreen mode

Now we are ready to use Virtual Scroll!

We will modify our application to use Virtual Scroll! Here is link to stackblitz app with desired state. This is same as our initial app but with Angular CDK installed and imported.

Open app.component.ts, inside the constructor of AppComponent you will see

constructor()  {
  this.persons =  Array(100).fill(0).map(()  =>  { 
  return {
      name: faker.name.findName(),
      bio: faker.hacker.phrase(),
      avatar: faker.image.business()
    }
  })
}
Enter fullscreen mode Exit fullscreen mode

What this does is creates an array of 100 objects, each object contains name, bio and avatar generated by faker. This array is assigned to instance variable called persons

Now open the template file for this component (app.component.html).

<div  class="search-wrapper cf">
  <input  type="text">
  <button (click)="undefined">Go To</button>
</div>

<div *ngFor="let person of persons;let i = index">
  <div class="card">
      <img  src="https://i.imgur.com/63S0RAq.png"  alt="Avatar">
      <div  class="container">
        <h4><b>{{person.name}}</b></h4>
        <h4><b>ID: {{i}}</b></h4>
        <p>{{person.bio.substr(0, 30)}}</p>
      </div>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

The template consist of a button with click handler defined as of now it does nothing. Below the button we are using *ngFor to iterate over person array, for each person array we create a div with class card. This card div consist person's name, id, bio and avatar. We are displaying only first 30 characters of bio.

Now let's modify our template to use Virtual Scroll. For this first we need to wrap our ngFor with <cdk-virtual-scroll-viewport> and then replace *ngForwith . cdk-virtual-scroll-viewport has a required input called [itemSize].

itemSize represents the height of item in pixels which we are rendering in our case this should be exact height of our card div which is 141px. Another thing to note is that height of all of our cards component should be same. As of now the Virtual Scroll does not support fully support variable height. We will look into matter of variables heights later.

so lets wrap our *ngFor with cdk-virtual-scroll-viewport and replace our *ngForwith *cdkVirtualFor. Another thing which needs to be done before we see any visual change is giving height to our cdk-virtual-scroll-viewport I want to show two user cards at once so I will give cdk-virtual-scroll-viewport height of 282px (size of single card is 141, 141 * 2 = 282) you can either give height in stylesheet our add style tag. I will be adding height via style tag

<cdk-virtual-scroll-viewport [itemSize]="141" style="height: 282px">
<div *cdkVirtualFor="let person of persons;let i = index">
  <div  class="card">
    <img  src="https://i.imgur.com/63S0RAq.png"  alt="Avatar">
    <div  class="container">
        <h4><b>{{person.name}}</b></h4>
        <h4><b>ID: {{i}}</b></h4>
        <p>{{person.bio.substr(0, 30)}}...</p>
    </div>
</div>

</div>
</cdk-virtual-scroll-viewport>
Enter fullscreen mode Exit fullscreen mode

Now we can see that our user list items are rendered. Lets verify that we DOM items are created dynamically and reused. Open your browser developers tools, select Elements Panel. Find the DOM element shown in screen shot below and expand it.

Virtual Scroll in dev tools

Now if you scroll through the list you will see that limited number of DOM elements are created, which leads to reduce memory and cpu usage.

Items with variable heights

As of now Virtual Scroll does not support variable heights, but it is being worked on and is in experimental phase which means you should not use it in production as its api may change.

For items with variable height we need to install @angular/cdk-experimental. You can install into stackblitz by click on dependencies and type @angular/cdk-experimentaland hit enter. It will install the experimental cdk for you. User of angular cli can install it by npm @angular/cdk-experimental.

Now we need to import it into our app module. Just like before, add following line in app.module.ts

import  {  ScrollingModule  as  ExperimentalScrollingModule}  from  '@angular/cdk-experimental/scrolling';```


It will import `ScrollingModule` and rename it as `ExperimentalScrollingModule`. We need both `ScrollingModule` and `ExperimentalScrollingModule` for variable height to work. Now add `ExperimentalScrollingModule` into import array. You `app.module.ts` should look like this:


```import  {  NgModule  }  from  '@angular/core';
import  {  BrowserModule  }  from  '@angular/platform-browser';
import  {  FormsModule  }  from  '@angular/forms';
import  {  AppComponent  }  from  './app.component';
import  {  ScrollingModule  }  from  '@angular/cdk/scrolling';
import  {  ScrollingModule  as  ExperimentalScrollingModule}  from  '@angular/cdk-experimental/scrolling';

@NgModule({
imports:  [  BrowserModule,  FormsModule,  ScrollingModule,  ExperimentalScrollingModule  ],
declarations:  [  AppComponent  ],
bootstrap:  [  AppComponent  ]
})
export  class  AppModule  {  }
Enter fullscreen mode Exit fullscreen mode

Now open app.component.html and replace [itemSize] with autosize. Thats it! Now you can elements of variable height in your Virtual Scroll but as said before this feature is experimental and should not be used. You can find example for autosize here

Discussion (0)