Building infinite virtual scrolling lists with the new Angular 7 CDK

Introduction

TL;DR:In this tutorial, we will learn about and take a good look at how to use the infinite virtual scroll tool in the Angular Material Component Development Kit.

Introduction

Angular is a JavaScript (TypeScript) framework for building web applications, mobile or desktop with over 42,000 stars️ on GitHub. It is maintained by the Angular team at Google and a host of community members and organizations. Angular version 7.0 was released some months ago. One of the features it shipped with is the virtual scroll tool in the Component Development Kit.

Component Development Kit (CDK)

The Component Development Kit is a set of tools that implement common behaviors and components with very unique interaction styles without being opinionated about the template choices. It is a kind of abstraction of the Angular Material Library, with no styling specific to material design. It provides more unique ways to get creative while building your Angular components.

Understanding the process

Most times when we work with really long lists in our presentation layer in Angular, we think of additional features to make the experience better. This can be like adding pagination or “next” button or even a “load more” button. The Component Development Kit has a scrolling feature that now helps us to have a better and more dynamic way of rendering these long lists of items in a way that is most efficient and with the lowest cost.

What you will learn

By building different fragments of a long list in this tutorial with the virtual scrolling CDK you will learn how to use basic best practises of using Angular and the Component Development Kit to build dynamic lists that will load and remove list items from the DOM just by scrolling. You get to see only the subset of the list you want to see at a particular time both on your frontend and in the DOM.

Prerequisites

To be able to follow through in this article’s demonstration you should have:

  • Node version 11.0 installed on your machine.
  • Node Package Manager version 6.7 (usually ships with Node installation).
  • Angular CLI version 7.0
  • The latest version of Angular (version 7)
1// run the command in a terminal
2    ng version

Confirm that you are using version 7, and update to 7 if you are not. Other things that will be nice-to-haves are:

  • A working knowledge of the Angular framework at a beginner level.
  • Familiarity with Angular services will be a plus but not a requirement.

Setting up

We will go through the process of setting up the development environment and installing all the required dependencies for the Component Development Kit to work.

Generating an Angular 7 application

1//cd to a preferred location
2    // run the command below
3    ng new virtualscroll

You do not need Angular routing, but you have to choose CSS for styling. Now, we get Angular Material installed on the above app

    ng add @angular/material

You can choose any pre-built theme of your choice or create one yourself (we used indigo-pink). For this tutorial, you do not need HammerJs or the Animations module. Angular Material ships with the Component Development Kit where our virtual scrolling module is located. Then, import the scrolling module in the app module so it is available for use in the Angular application so that the import section will look like so:

1// src/app/app.module.ts
2    import { BrowserModule } from '@angular/platform-browser';
3    import { NgModule } from '@angular/core';
4    import { AppComponent } from './app.component';
5    import { ScrollingModule } from '@angular/cdk/scrolling'
6    import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
7    import { ArtistsComponent } from './artists/artists.component';

Add this the scrolling module to the import section so it would look like this:

1imports: [BrowserModule,
2             ScrollingModule
3           ]

Creating a list

We will create an exportable data object in a new file we will call data.ts ``and then use an Angular service to expose the data to any component that imports it.

Create a new file in the app folder called data.ts and then populate it with artists like thus:

1// src/app/data.ts
2    
3    export const artists = [
4    {
5    number: "1",
6    name: "Davido"
7    },
8    {
9    number: "2",
10    name: "Wizkid"
11    },
12    {
13    number: "3",
14    name: "Burna Boy"
15    },
16    {
17    number: "4",
18    name: "Patoranking"
19    },
20    {
21    number: "5",
22    name: "Maleek Berry"
23    },
24    {
25    number: "6",
26    name: "Mr. Eazi",
27    },
28    {
29    number: "7",
30    name: "Mayorkun"
31    },
32    {
33    number: "8",
34    name: "Peruzzi"
35    },
36    {
37    number: "9",
38    name: "Teni"
39    },
40    {
41    number: "10",
42    name: "Olamide"
43    },
44    {
45    number: "11",
46    name: "Phyno"
47    },
48    {
49    number: "12",
50    name: "M.I"
51    },
52    {
53    number: "13",
54    name: "Ycee"
55    },
56    {
57    number: '14",
58    name: "Dremo"
59    },
60    {
61    number: "15",
62    name: "Zlatan"
63    },
64    {
65    number: "16",
66    name: "Reminnisce"
67    },
68    {
69    number: "17",
70    name: "Tiwa Savage"
71    },
72    {
73    number: "18",
74    name: "Seyi Shay"
75    },
76    {
77    number: "19",
78    name: "Blaqbonez"
79    },
80    {
81    number: "20",
82    name: "Tekno"
83    },
84    {
85    number: "21",
86    name: "Niniola"
87    }
88    ]

Create a service called artists with this command in your project terminal:

    ng g service artists

This generates a service called artists in your app component. You can add the flag to remove the test spec file like this:

    ng g service --skipTests artists 

You should see a new file in the app folder called artists.service.ts ``and it should look like this:

1// src/app/artists.service.ts
2    
3    import { Injectable } from ‘@angular/core’;
4    import { artists } from './data'
5    @Injectable({
6    providedIn: ‘root’
7    })
8    export class ArtistsService {
9     constructor() { }
10    }

To bring in the data to be used by the artists service, we return artists (as specified in the export statement in the data) in the constructor like so:

1// src/app/artists.service.ts
2    
3    export class ArtistsService {
4     constructor() { }
5      getArtists(){
6       return artists;
7       }
8     }

Now we have to create a component for the artists where we can populate the hard coded data we have. Run the command below:

    ng g component -skipTests artists

This creates a component called artists and we can then pull the data on the artists service to the artists component using the lifecycle method when the component initializes like this:

1// src/app/artists/artists.component.ts 
2    import { Component, OnInit } from '@angular/core';
3    import { ArtistsService } from '../artists.service';
4    @Component({
5      selector: 'app-artists',
6      templateUrl: './artists.component.html',
7      styleUrls: ['./artists.component.css']
8    })
9    export class ArtistsComponent implements OnInit {
10     constructor(private artistsService: ArtistsService) { }
11      artists = [];
12      ngOnInit() {
13       this.getArtists();
14      }
15      getArtists (){
16       this.artists = this.artistsService.getArtists();
17       }
18     }

Clear everything currently in the app.component.html and just replace with this selector instead:

    <app-artists></app-artists>

Creating items

Now that we have brought in the data through the artists service, let’s deal with the presentation and styling. To implement virtual scrolling in the user interface, Angular provides an HTML-like tag that tells Angular that the content inside the tag will have virtual scrolling implemented.

That is the <cdk-virtual-scroll-viewport> tag and when you want to use the virtual scrolling feature, Angular provides a special ngFor for you to use instead of the regular one. It is called *cdkVirtualFor and it does exactly the same thing as ngFor only that ngFor can not be used inside the virtual scroll tag.

It is compulsory to set the itemSize property on the viewport, as it will return an error if omitted.

*cdkVirtualFor has a few variables you can use for logic on your template:

  • index : the index of the item in the data source.
  • count : the total number of items in the data source.
  • first : whether this is the first item in the data source.
  • last : whether this is the last item in the data source.
  • even: whether the index is even.
  • odd: whether the index is odd.

It is important to note that all these variables apply to the item index in the data source not in the rendered data. Normally, to display the artists, we have to use ngFor syntax like this:

1// src/app/artists/artists.component.html
2    <div class="container">
3      <h2>Brits Performing artists</h2>
4      <div class="example-viewport">
5        <div *ngFor="let artist of artists" class="list">
6          <h2>{{artist.name}}</h2>
7        </div>
8      </div>
9    </div>

Now, we use the virtual scroll syntax like this:

1// src/app/artists/artists.component.ts 
2    <div class="container">
3      <h2>Brits Performing artists</h2>
4      <cdk-virtual-scroll-viewport itemSize="100" class="example-viewport">
5     <div *cdkVirtualFor="let artist of artists" class="list">
6       <h2>{{artist.name}}</h2>
7      </div>
8      </cdk-virtual-scroll-viewport>
9    </div>

We can then style the viewport and the list items like this:

1// src/app/artists/artists.component.css
2    
3    .example-viewport{
4     height: 250px;
5     width: 25%;
6     margin-left: 50px;
7     border: 1px solid saddlebrown;
8     display: flex;
9    }
10    .list{
11     height: 50px;
12     justify-content: center;
13     align-items: center;
14    }
15    h2{
16     margin-left: 40px;
17    }
18    .container{
19     margin-bottom: 40px;
20    }

You can now run your application in development environment with the command

    ng serve

Open your browser at http://localhost:4200/ and you should see your application like this:

angular-infinite-scroll-demo-1

If you take a look at the developer tools and inspect the elements section, you will notice that list items are added and removed from the DOM dynamically as you scroll. That is the awesome power of the virtual scrolling feature that shipped with the Component Development Kit.

Demo: a simple use case

If you have followed the article to this point, you must have by now started to have some ideas of how to implement the virtual scrolling feature in your next project. One of these use cases can be to create a hall of fame list featuring performers from the annual BRITs awards.

What we will be building

angular-infinite-scroll-demo-2

Coding the hall of fame

The few modifications made to achieve this demo above were done in the following component files: Add the following to the artists.component.html file:

1// src/app/artists/artists.component.html
2    
3    <h1>Brits Performance Hall of Fame</h1>
4    <div class="container">
5      <h2>2019 Artists</h2>
6      <cdk-virtual-scroll-viewport itemSize="100" class="example-viewport">
7      <div *cdkVirtualFor="let artist of artists" class="list">
8        <h2>{{artist.number}}. {{artist.name}}</h2>
9      </div>
10      </cdk-virtual-scroll-viewport>
11    </div>
12    <div class="container">
13      <h2>2018 Artists</h2>
14      <cdk-virtual-scroll-viewport itemSize="100" class="example-viewport">
15      <div *cdkVirtualFor="let artist of artists" class="list">
16        <h2>{{artist.number}}. {{artist.name}}</h2>
17      </div>
18      </cdk-virtual-scroll-viewport>
19    </div>
20    <div class="container">
21      <h2>2017 Artists</h2>
22      <cdk-virtual-scroll-viewport itemSize="100" class="example-viewport">
23      <div *cdkVirtualFor="let artist of artists" class="list">
24        <h2>{{artist.number}}. {{artist.name}}</h2>
25      </div>
26      </cdk-virtual-scroll-viewport>
27    </div>

Add the following to the artists.component.css file

1// src/app/artists/artists.component.css
2    
3    .example-viewport{
4      height: 250px;
5      width: 25%;
6      margin-left: 50px;
7      border: 1px solid saddlebrown;
8      display: flex;
9    }
10    .list{
11      height: 80px;
12      justify-content: center;
13      align-items: center;
14    }
15    h2{
16      margin-left: 40px;
17    }
18    h1{
19      margin-left: 18px;
20    }
21    .container{
22      margin-bottom: 40px;
23      display: flex;
24    }

Add the following to the artists.components.ts file

1import { Component, OnInit } from '@angular/core';
2    import { ArtistsService } from '../artists.service';
3    @Component({
4    selector: 'app-artists',
5    templateUrl: './artists.component.html',
6    styleUrls: ['./artists.component.css']
7    })
8    export class ArtistsComponent implements OnInit {
9     constructor(private artistsService: ArtistsService) { }
10      artists = [];
11      ngOnInit() {
12      this.getArtists();
13    }
14    getArtists (){
15      this.artists = this.artistsService.getArtists();
16      }
17     }

Your application should now be up to date with our demo, you can now run it in the development environment

    ng serve

Conclusion

The Component Development Kit provides a lot of features that helps developers enhance the development process of the user interface. This tutorial gives you a quick guide to the syntax and usage of the virtual scrolling feature. You can find the official documentation here. You can download the code in this tutorial from here. Documentation for other Angular Material CDK features can be found here.

Happy Coding!