1

I am trying to load 20 items through the virtual scroll component, but I see 34 as soon as the page loads, without doing any scrolling at all. Have I got the css wrong? Or there is some setting on the control that I forgot? The project is located here.

yunzen
  • 30,001
  • 10
  • 64
  • 93

2 Answers2

5

This tutorial on Firebase says:

Let’s start by reviewing a few important concepts with virtual scroll. First, you declare the cdk-virtual-scroll-viewport component to provide a context for virtual scrolling. It should have an itemSize input property defined as the pixel height of each item.

You can see that this is not made especially for grid scroll views, but we can work around this limitation:

You have 5 columns of images each 160 pixels high plus margins top and bottom each 10 pixels, yielding 180 pixels.

Now we calculate 180 divided by 5 and get 36. This is the itemSize you need.

<cdk-virtual-scroll-viewport itemSize="36">
  <div class="image" *cdkVirtualFor="let image of images">
    <a (click)="viewDetail(image)">
      <img src="https://picsum.photos/200/160/?image={{ image.id }}" />
    </a>
  </div>
</cdk-virtual-scroll-viewport>

See this fork of your StackBlitz

The official documentation is here: Angular | Scrolling

You could change the buffer sizes as well

<cdk-virtual-scroll-viewport itemSize="36" minBufferPx="540" maxBufferPx="540">
  <!-- ... -->
</cdk-virtual-scroll-viewport>

See: Angular | Scrolling # Scrolling over fixed size items

You can also let Angular do the math:

<cdk-virtual-scroll-viewport itemSize="{{ 180 / 5 }}" minBufferPx="{{ 180 * 3 }}" maxBufferPx="{{ 180 * 3 * 3 }}">

That means that you will load three pages (3 rows per page) in advance and load more if only one page buffer (3 rows of images per page) is left

yunzen
  • 30,001
  • 10
  • 64
  • 93
0

One Idea is to load only a couple of items and using an Observer to load next bunch of items

<cdk-virtual-scroll-viewport 
     itemSize="10" 
     minBufferPx="1200" 
     maxBufferPx="1200" 
     (scrolledIndexChange)="getNextBatch($event)">
  ...
</cdk-virtual-scroll-viewport>
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { ImageService } from '../image.service';
import { Subscription } from 'rxjs';
import { Router } from '@angular/router';
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';

@Component({
  selector: 'app-gallery',
  templateUrl: './gallery.component.html',
  styleUrls: ['./gallery.component.css'],
})
export class GalleryComponent implements OnInit, OnDestroy {
  @ViewChild(CdkVirtualScrollViewport) viewport: CdkVirtualScrollViewport;

  constructor(public service: ImageService, private router: Router) {}

  ...

  getNextBatch(e) {
     const end = this.viewport.getRenderedRange().end;
     const total = this.viewport.getDataLength();

     console.log(end)
     console.log(total)

     if (end === total) {
        console.log('request next batch');
     }
  }
}

magic.77
  • 536
  • 4
  • 14