November 27, 2018
Improve performance with virtual scrolling in Angular – HowTo
Since the release of Angular 7, the Angular CDK includes a feature that can improve the performance of your application dramatically. Virtual scrolling is highly beneficial for dealing with a lot of data in tables or lists. You can improve performance for large lists in Angular with the Angular CDK virtual scrolling component.
What is virtual scrolling
I could explain what virtual scrolling is, but I couldn’t do it as good as some other folks, so I’m going to recommend that you watch the following talk instead. The first 5 minutes should give you a rough idea.
What is the Angular CDK
The feature is not included in the @angular/core package but is bundled within the Angular CDK.
The Component Dev Kit (CDK) is a set of tools that implement common interaction patterns whilst being unopinionated about their presentation.
https://material.angular.io/cdk/categories
In more simpler terms you could say, that the CDK is the backbone of Angular Material and provides the base functionality without including any styling.
Virtual scrolling performance demo time
The code we are looking at in this post is hosted on Stackblitz: https://stackblitz.com/edit/angular-virtual-table-scrolling
Start with a plain Angular table
We’re starting with a pretty simple example of a table using a *ngFor loop
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<table> <thead> <tr> <td>Name</td> <td>ID</td> </tr> </thead> <tbody> <tr *ngFor="let row of tableData"> <td>{{row.name}}</td> <td>{{row.id}}</td> </tr> </tbody> </table> |
We define the tableData property in the corresponding component.ts file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// app.component.ts import { Component, OnInit} from '@angular/core'; @Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: [ './app.component.css' ] }) export class AppComponent implements OnInit { name = 'Angular'; tableData = []; ngOnInit() { for (let i = 0; i < 1000; i++) { this.tableData.push({ name: 'Name' + i, id: i }); } } } |
Introducing virtual scrolling
The Angular CDK provides a scrolling component. We’re now going to add it to our plain table in 4 simple steps.
1. Add the dependency
1 |
npm install @angular/cdk --save |
2. Add ScrollingModule
1 2 3 4 5 6 7 |
//app.module.ts import { ScrollingModule } from '@angular/cdk/scrolling'; @NgModule({ imports: [ ScrollingModule ], }) export class AppModule { } |
3. Add virtual scrolling component
Step 2 is to add the <cdk-virtual-scroll-viewport> element around the markup of your table. We need to provide the attribute [itemSize]=”heightOfRowInPx” that tells the scrolling component how high each row is.
4. Replace *ngFor with *cdkVirtualFor
Instead of using *ngFor we’re going to use *cdkVirtualFor. This way the virtual scrolling works as intended.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<cdk-virtual-scroll-viewport [itemSize]="20"> <table> <thead> <tr> <td>Name</td> <td>ID</td> </tr> </thead> <tbody> <tr *cdkVirtualFor="let row of tableData"> <td>{{row.name}}</td> <td>{{row.id}}</td> </tr> </tbody> </table> </cdk-virtual-scroll-viewport> |
Result
If we inspect the DOM changes after introducing the <cdk-virtual-scroll-viewport> we see that the browser is removing and adding DOM Nodes as we are scrolling.
Improvements / Hints
- Depending on the layout of your application you might need to set a height for the <cdk-virtual-scroll-viewport> element.
- Use the trackBy function of *ngFor whenever you can like shown here.
- For more information on how to optimize performance when loading big and expensive lists, we recommend you our blog post regarding this topic.
Alternatives
One thing that is obvious while using angular CDK virtual scrolling, is that it comes with quiet a lot of magic. The options to fine tune the virtual scrolling behaviour are limited. If you are interested in alternatives to optimize the loading of large lists or lists with expensive elements, we encourage you to have a look at ngx-infinite-scroll.
Infinite-scroll has the same goal as virtual scrolling, yet the strategy differs a bit. While virtual scrolling only renders the list the visible elements, infinite scroll loads the elements lazy. So if I scroll down the list and reach a defined area at the end of the already loaded elements, it triggers a function that loads the next x elements. The same can be implemented for scrolling up.
One big benefit of using infinite scrolling is the control you get over the displayed items. So if you want all loaded items to be available after they have been loaded lazily, infinite scroll is your friend.
Further Reading
I want to use virtual scroll for column also. is it possible for nested virtual scroll
[…] Check this out for a full implementation. […]
is there any example without using CDK means custom virtual scrolling component?
can I use it on the whole page not a specific view port – I am trying to avoid scrolling inside the page
That was a great thing I have learnt today.
how does virtual scroling work for nested table
will search work with virtual scrolling??