Virtual Scrolling

By importing ScrollingModule the newly added CDK can take advantage of the VirtualScrolling. When we have to define Virtual Scrolling, then it is loading or unloading of the DOM elements based on the noticeable aspects of the list. Now, Google has accelerated the speed of the huge scrollable lists.

Based on the visible parts of a list, virtual Scrolling loads and unloads elements from the DOM and make it possible to build very fast experiences for users with very large scrollable lists.

The <cdk-virtual-scroll-viewport> displays large lists of elements efficiently by only providing the items that fit on-screen. Loading hundreds of elements at a time can be slow in any browser. Virtual scrolling enables an effective way to simulate all items being provided by making the height of the container element the same as the height of the total number of elements to be rendered, and then only providing the items in view. Virtual scrolling is different from strategies like infinite scroll where it renders a set of elements and then renders the rest when you hit the end.

cdkScrollable and ScrollDispatcher

The cdkScrollable directive and the ScrollDispatcher service jointly permit components to react to scrolling in any of its ancestor scrolling containers.

The cdkScrollable directive must be applied to that element that acts as a scrolling container and this marks the element as a Scrollable and registers it with the ScrollDispatcher. The dispatcher then allows components to share both event listeners and knowledge of all the scrollable containers in the application.

ViewportRuler

The ViewportRuler is a service which will be injected and is used to measure the bounds of the browser viewport.

Basic virtual scroll

*ngFor is replaced by *cdkVirtualFor inside of a <cdk-virtual-scroll-viewport> , supporting the exact same API as *ngFor. The simplest usage just describes the list of items (note that the itemSize property on the viewport must be set).

Example

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ScrollingModule } from '@angular/cdk/scrolling';
@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ScrollingModule,
    BrowserAnimationsModule
  ],
  exports: [
    BrowserAnimationsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
import {ChangeDetectionStrategy, Component} from '@angular/core';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  items = Array.from({length: 100000}).map((_, i) => `Item #${i}`);
}
.example-viewport {
  height: 200px;
  width: 200px;
  border: 1px solid black;
  margin-top: 150px;
  margin-left: 50px;
}

.example-item {
  height: 50px;
}
<cdk-virtual-scroll-viewport
    itemSize="50"
    class="example-viewport"
>
    <div
        *cdkVirtualFor="let item of items"
        class="example-item"
    >
        {{item}}
   </div>
</cdk-virtual-scroll-viewport>
SahosoftTutorials-BasicVirtualScrolling

*cdkVirtualFor makes the following context variables available to the template:

Context variable Description
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.

All of these apply to the index of the item available in the data source, not to the index of the rendered portion of data.

Example

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { DragDropModule } from '@angular/cdk/drag-drop';
@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    DragDropModule,
    BrowserAnimationsModule
  ],
  exports: [      
    BrowserAnimationsModule  
  ],      
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
import { Component } from '@angular/core';
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  movies = [
    '1. How to upgrade to Angular 7',
    '2. Angular 7 CLI Prompts',
    '3. Application Performance',
    '4. Documentation Updates',
    '5. Dependency Updates',
    '6. Drag and Drop',
    '7. Virtual Scrolling',
    '8. Improved Accessibility of Selects',
    '9. Partner Launches',
    '10. Angular Elements'
  ];

  drop(event: CdkDragDrop<string[]>) {
    moveItemInArray(this.movies, event.previousIndex, event.currentIndex);
  }
}
}
.example-list {
    width: 500px;
    max-width: 100%;
    border: solid 1px #ccc;
    min-height: 60px;
    display: block;
    background: white;
    border-radius: 4px;
    overflow: hidden;
    margin-left: 300px;
    margin-top: 50px;
}

.example-box {
  padding: 20px 10px;
  border-bottom: solid 1px #ccc;
  color: rgba(0, 0, 0, 0.87);
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  box-sizing: border-box;
  cursor: move;
  background: white;
  font-size: 14px;
}

.cdk-drag-preview {
  box-sizing: border-box;
  border-radius: 4px;
  box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
              0 8px 10px 1px rgba(0, 0, 0, 0.14),
              0 3px 14px 2px rgba(0, 0, 0, 0.12);
}

.cdk-drag-placeholder {
  opacity: 0;
}

.cdk-drag-animating {
  transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}

.example-box:last-child {
  border: none;
}

.example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) {
  transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
<cdk-virtual-scroll-viewport [itemSize]="18 * 7" class="example-viewport">
    <div *cdkVirtualFor="let item of items;
                         let index = index;
                         let count = count;
                         let first = first;
                         let last = last;
                         let even = even;
                         let odd = odd;" [class.example-alternate]="odd">
     <div class="example-item-detail">Item: {{item}}</div>
     <div class="example-item-detail">Index: {{index}}</div>
      <div class="example-item-detail">Count: {{count}}</div>
      <div class="example-item-detail">First: {{first ? 'Yes' : 'No'}}</div>
      <div class="example-item-detail">Last: {{last ? 'Yes' : 'No'}}</div>
      <div class="example-item-detail">Even: {{even ? 'Yes' : 'No'}}</div>
      <div class="example-item-detail">Odd: {{odd ? 'Yes' : 'No'}}</div>
    </div>
 </cdk-virtual-scroll-viewport>
SahosoftTutorials-ngForVirtualScrolling

The specification and working of a trackBy function are same as for the *ngFor trackBy. The index passed to the tracking function will be the index in the data source, not the index in the given portion.

Note:To read more go to material.angular.io