14

Does any one met the issue of angular 7 cdk virtual scrolling working abnormally in mat-tab group.

https://github.com/angular/material2/issues/13981

My city component template looks like that

<cdk-virtual-scroll-viewport class="list-container" [itemSize]="50" minBufferPx="200" maxBufferPx="400" (scrolledIndexChange)="getNextBatch($event)">
  <div *cdkVirtualFor="let state of statesObservable | async; trackBy: trackByFn" class="list-group-item state-item">
    <div class="state">{{state.name}}</div>
    <div class="capital">{{state.capital}}</div>
  </div>
</cdk-virtual-scroll-viewport>

When put this city component to the mat-tab-group as the second tab

<mat-tab-group>
  <mat-tab label="Country">
    <app-country></app-country>
  </mat-tab>
  <mat-tab label="City">
    <app-city></app-city>
  </mat-tab>
</mat-tab-group>

The result looks like belenter image description hereow:

The stackblitz code is here: https://stackblitz.com/edit/angular7-virtual-scroll-issue

Does anyone have some idea for this issue?

Gonçalo Peres
  • 11,752
  • 3
  • 54
  • 83
rodent_la
  • 1,195
  • 4
  • 18
  • 38

5 Answers5

11

You tell it to keep the Buffer size between 200px and 400px, yet your scroll window is much taller than that.

Change both the minimum and maximum to 1200px, this will keep the items cover your viewport, even when you scroll down for more items.

https://stackblitz.com/edit/angular7-virtual-scroll-issue-ftcnng

Per Hornshøj-Schierbeck
  • 15,097
  • 21
  • 80
  • 101
11

You need to lazy load the tab content by declaring the body in a ng-template with the matTabContent attribute. This way, the viewport size is calculated only when the tab is shown.

  <mat-tab label="City">
    <ng-template matTabContent>
      <app-city></app-city>
    </ng-template>
  </mat-tab>

See: https://material.angular.io/components/tabs/overview#lazy-loading

Liviu
  • 111
  • 1
  • 2
4

The question has been asked some time ago, but there is a solution which is not a workaround.

First you need the Viewport Reference:

@ViewChild(CdkVirtualScrollViewport, {static: false}) cdkVirtualScrollViewport: CdkVirtualScrollViewport;

Then you can call the Method checkViewportSize() when the size of the Viewport has changed. Before you call this method you need to update the style height of the Viewport container.

this.heightChange$.subscribe(() => {
    this.cdkVirtualScrollViewport.checkViewportSize();
});
  • This is the correct answer. It will also update maxBufferPx & minBufferPx to work as described (*additional buffer off the screen*). I am using this fix on multiple projects. – Cooper Scott Dec 30 '21 at 19:38
  • This is what worked for me as well. I had a situation where the virtual scroll's viewport was in a flex-box, so it needed to respond to what the flex's layout would be. When it was initialized, it was less than what it needed to be. Calling this after the view was initilaized made it take up the entire space it could. – Julia Norman Apr 01 '22 at 17:42
1

Works for me, thanks!

  @ViewChild(CdkVirtualScrollViewport) viewport: CdkVirtualScrollViewport;

  @HostListener('window:resize', ['$event'])
  onResize(event) {
    this.viewport.checkViewportSize();
  }
-1

Use ItemSize only. Avoid Max and Min Buffer.

<cdk-virtual-scroll-viewport class="list-container" [itemSize]="50" >

It needs to be the exact pixel height of a single item.

Mario Petrovic
  • 7,500
  • 14
  • 42
  • 62
Fred
  • 9
  • 1