Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Maintain scroll position with CDK autosize virtual scroll strategy

Maintain scroll position with CDK autosize virtual scroll strategy

I have a large list of items that can be scrolled with <cdk-virtual-scroll-viewport autosize> provided by @angular/cdk-experimental (the items have dynamic heights, thus I'm using this scroll strategy instead of the FixedSizeVirtualScrollStrategy).

New items are inserted in the list over time, i.e. they are appended on top. When the user scrolls down I want to avoid that new items will push the items in the viewport away. Therefore I need a mechanism to maintain / restore the scroll position after the items have been added.

I have a semi-working solution (and hacky because it reads private fields), but the viewport shifts a few pixels randomly after items have been added.

Here are the relevant code parts:

@ViewChild(CdkVirtualScrollViewport) viewport: CdkVirtualScrollViewport;

...

// After new items have been added:

const offset = this.viewport.measureScrollOffset('top');
const topPosition = offset + newItems.length * this.viewport['_scrollStrategy']._averager._averageItemSize; // the autosize strategy determines an average item size I'm trying to use to determine how the viewport should be shifted

this.viewport.scrollTo({
  top: topPosition
});

I created a demo of this approach here: https://stackblitz.com/edit/angular-be926g?file=src/app/cdk-virtual-scroll-overview-example.ts

Any ideas how to achieve this seamlessly with a constant viewport?

like image 914
Ulrich Lehner Avatar asked Nov 03 '20 15:11

Ulrich Lehner


People also ask

How does CDK virtual scroll work?

This feature is added to CDK (Component Development Kit). Virtual scrolling shows up the visible dom elements to the user, as the user scrolls, the next list is displayed. This gives faster experience as the full list is not loaded at one go and only loaded as per the visibility on the screen.

What is itemSize in CDK virtual scroll viewport?

[itemSize] dictates how tall in pixels each row in the list is. The virtual scroller then uses this (in part) to determine how many rows it can buffer above and below the viewport. The less tall you make the itemSize , the more it will try to load and buffer.

How can a fixed size scrolling strategy be added into the browsers viewport?

Scrolling over fixed size items When all items are the same fixed size, you can use the FixedSizeVirtualScrollStrategy . This can be easily added to your viewport using the itemSize directive.

What is virtual scrolling?

Virtual scrolling allows the Grid component to display thousands of records on a single page. You can use this feature as an alternative to paging. Browser Support Notes: The following browsers do not support virtual scrolling because they do not support position: sticky : Android Browser before 5.0.


1 Answers

you can use this.viewport.getRenderedRange() to check the viewport is on top and if zero then append the elements else keep the elements in a bucket and append the objects when user scrolled to top of viewport.

  const range = this.viewport.getRenderedRange();
  console.log("range", range);
  bucket = [...bucket, ...newItems];
  console.log("bucket", bucket);
  if (range.start == 0) {
    this.items = [...bucket.reverse(), ...this.items];
    bucket = [];
  }

stackblitz example

like image 57
Tony Avatar answered Sep 30 '22 14:09

Tony