components icon indicating copy to clipboard operation
components copied to clipboard

virtual-scroll: support items of unknown size

Open mmalerba opened this issue 6 years ago • 113 comments

Support virtual scrolling over a list of items whose size is not known and needs to be measured

mmalerba avatar Feb 23 '18 22:02 mmalerba

Been testing autosize and seems to work pretty well.

amcdnl avatar May 17 '18 14:05 amcdnl

Is this released? Or are any extra steps needed? I'm getting

ERROR Error: StaticInjectorError(AppModule)[CdkVirtualScrollViewport -> InjectionToken VIRTUAL_SCROLL_STRATEGY]: 
  StaticInjectorError(Platform: core)[CdkVirtualScrollViewport -> InjectionToken VIRTUAL_SCROLL_STRATEGY]: 

edit: looks like you need to have both

import { ScrollDispatchModule } from '@angular/cdk/scrolling';
import { ScrollingModule } from '@angular/cdk-experimental/scrolling';

imported for autosize to work

fxck avatar Oct 16 '18 09:10 fxck

Looking forward to see this feature! :+1:

webcat12345 avatar Oct 25 '18 10:10 webcat12345

It seems to be working fine in most of the time, except that there is always an empty space on the bottom that keeps increasing in size each time you scroll down and up a bit.

fxck avatar Oct 25 '18 10:10 fxck

@fxck could you please share some of your code to show how to use this feature?

webcat12345 avatar Oct 25 '18 13:10 webcat12345

Just import import { ScrollingModule } from '@angular/cdk-experimental/scrolling'; and use it with autosize directive.

<cdk-virtual-scroll-viewport [style.height.px]="height" autosize>
  <div *cdkVirtualFor="let item of list">{{ item }}</div>
</cdk-virtual-scroll-viewport>

fxck avatar Oct 25 '18 13:10 fxck

yes, it works for me :)

webcat12345 avatar Oct 25 '18 14:10 webcat12345

But if I use autosize strategy it can not use many functions such as scrollToIndex() ... Is there any alternative way? For example I am going to scroll to bottom

webcat12345 avatar Oct 25 '18 14:10 webcat12345

That's most likely the reason why this is experimental and not in stable. It's just not finished and feature complete yet.

fxck avatar Oct 25 '18 14:10 fxck

I see. I have tested autosize feature with a list of 121000 + different height items and it works well without any lag. :+1: Is there any ETA for this feature? (but with normal functions as well :) ) This is really cool. We are going to use this for our project and really want to see this to be released!!!

webcat12345 avatar Oct 25 '18 14:10 webcat12345

any update on this feature?

webcat12345 avatar Nov 05 '18 14:11 webcat12345

@mmalerba Any updates on this? Thanks

bop10 avatar Dec 07 '18 14:12 bop10

Will this be implemented in production soon?

flolu avatar Jan 03 '19 06:01 flolu

I've been trying to get autosize strategy to work based on fxck's example, but keep getting this error: "Can't bind to 'cdkVirtualForOf' since it isn't a known property of 'div'. " Any suggestions?

salsadoka avatar Jan 30 '19 21:01 salsadoka

I've been trying to get autosize strategy to work based on fxck's example, but keep getting this error: "Can't bind to 'cdkVirtualForOf' since it isn't a known property of 'div'. " Any suggestions?

Try with the cdk version angular 6.0.2

ravanasa avatar Feb 07 '19 05:02 ravanasa

any updates ? 7.0.4 angular say - Can't bind to 'cdkVirtualForOf'
angular 6.4.7 bug with autosize ( end scroll with space )

easyproger avatar Mar 07 '19 05:03 easyproger

any updates ? 7.0.4 angular say - Can't bind to 'cdkVirtualForOf' angular 6.4.7 bug with autosize ( end scroll with space )

Have you tried importing both the core and experimental scroll modules? I found this alleviated the Can't bind to cdkVirtualForOf issue.

import { ScrollingModule } from '@angular/cdk/scrolling';
import { ScrollingModule as ExperimentalScrollingModule} from '@angular/cdk-experimental/scrolling';

@NgModule({
  declarations: [
    AppComponent  
  ],
  imports: [
    BrowserModule,  
    ScrollingModule,
    ExperimentalScrollingModule,    
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

jonnyleeharris avatar Mar 13 '19 12:03 jonnyleeharris

But if I use autosize strategy it can not use many functions such as scrollToIndex() ... Is there any alternative way? For example I am going to scroll to bottom

I am scrolling to the bottom as follows:

    let top = this.viewport.measureScrollOffset("top");
    let bottom = this.viewport.measureScrollOffset("bottom");
    let offset = top + bottom;    
    this.viewport.scrollToOffset(offset);

However, there are a few layout bugs it appears - but it's to be expected since it is still an experimental feature.

jonnyleeharris avatar Mar 13 '19 15:03 jonnyleeharris

Any updates on this?

LeonadoRivaldo avatar Mar 13 '19 17:03 LeonadoRivaldo

any updates ? 7.0.4 angular say - Can't bind to 'cdkVirtualForOf' angular 6.4.7 bug with autosize ( end scroll with space )

Have you tried importing both the core and experimental scroll modules? I found this alleviated the Can't bind to cdkVirtualForOf issue.

import { ScrollingModule } from '@angular/cdk/scrolling';
import { ScrollingModule as ExperimentalScrollingModule} from '@angular/cdk-experimental/scrolling';

@NgModule({
  declarations: [
    AppComponent  
  ],
  imports: [
    BrowserModule,  
    ScrollingModule,
    ExperimentalScrollingModule,    
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

yeah but im get error - itemSize need to be set... if im set 0, ofc scroll load all items... if set any size scroll work not like autosized (((

easyproger avatar Mar 14 '19 19:03 easyproger

I have this:

"@angular/cdk": "^7.3.3",
"@angular/cdk-experimental": "7.3.3",
import { ScrollingModule } from '@angular/cdk-experimental/scrolling';
import { ScrollDispatchModule } from '@angular/cdk/scrolling';

imports: [ScrollDispatchModule, ScrollingModule],

And everything works ok with autosize.

BleedingDev avatar Mar 21 '19 14:03 BleedingDev

@easyproger What worked for me is itemSize="50" for the cdk-virtual-scroll-viewport and [style.height]="'auto'" on the li without any additional height styles applied.

I am importing both

import { ScrollingModule } from '@angular/cdk/scrolling';
import { ScrollingModule as ExperimentalScrollingModule } from '@angular/cdk-experimental/scrolling';

P.S. for some reason adding autosize causing occasional empty space without any list items at the bottom of the viewport.

Fleeck avatar Mar 28 '19 11:03 Fleeck

I tried to integrate mat-expansion-panels as list items. It's causing a few bugs while scrolling.

  1. I click on one item to open it
  2. I scroll down
  3. Suddenly other elements are open as well even if I didn't open them manually. The scrolling behaviour is not smooth anymore.

Does anybody know a workaround for this?

Apokryph avatar Apr 04 '19 09:04 Apokryph

Any update on this? Particularly the re-introduction of the scrolledIndexChange event with variable height items. Unless anyone knows of a work-around to be able to identify when the bottom of the list has been scrolled to, so that I know to fetch more data from the back-end?

ste-rob7 avatar Apr 16 '19 07:04 ste-rob7

@mmalerba in Ionic the item height is optional, but when it is provided, the calculation after scrolling into a new item is skipped, resulting in a better performance:

https://github.com/ionic-team/ionic/blob/master/angular/src/directives/virtual-scroll/virtual-scroll.ts

  /**
   * An optional function that maps each item within their height.
   * When this function is provides, heavy optimizations and fast path can be taked by
   * `ion-virtual-scroll` leading to massive performance improvements.
   *
   * This function allows to skip all DOM reads, which can be Doing so leads
   * to massive performance
   */
  itemHeight?: ItemHeightFn;

Perhaps you can implement it in a similar way for Material?

philly-vanilly avatar Apr 16 '19 08:04 philly-vanilly

I tried to integrate mat-expansion-panels as list items. It's causing a few bugs while scrolling.

  1. I click on one item to open it
  2. I scroll down
  3. Suddenly other elements are open as well even if I didn't open them manually. The scrolling behaviour is not smooth anymore.

Does anybody know a workaround for this?

I would expect it have something to do with how caching works - try setting templateCacheSize: 0 on the cdkVirtualFor and test it out.

maciekprzysowa avatar Apr 19 '19 07:04 maciekprzysowa

Any update on this? Particularly the re-introduction of the scrolledIndexChange event with variable height items. Unless anyone knows of a work-around to be able to identify when the bottom of the list has been scrolled to, so that I know to fetch more data from the back-end?

You have found any solution or work-around? Same problem here.

pauloeli avatar May 12 '19 23:05 pauloeli

Also has someone else experienced this bug ? https://angular-virtualdom-bug.stackblitz.io/ With 2 or 3 items inside the virtual scroll (depend on the height of your item) if you scroll fast to the top (once you are at the bottom) one element disappear

alexdabast avatar May 24 '19 08:05 alexdabast

Any news here? This is ne of my most wanted features.

SvenBudak avatar Jun 14 '19 13:06 SvenBudak

I'm going to be on vacation for most of July, but I've increased the priority as its something I'd like to work on after I get back

mmalerba avatar Jun 14 '19 16:06 mmalerba

Will this strategy support dynamic height of the viewport too?

lppedd avatar Jun 18 '19 10:06 lppedd

This is great! Are there any plans to integrate this with Material Flat Trees directly? I have documents with large tree structures (with leaves of different sizes) that I would like to display side by side. Virtual scrolling seems to work pretty well when rendering the flattened tree structure manually within the viewport. It would be awesome if I could just activate virtual scrolling with a setting in FlatTreeControl or so...

samuelblattner avatar Aug 01 '19 11:08 samuelblattner

I check every day about 10 times this issue, cant wait to get this feature 👍

SvenBudak avatar Aug 01 '19 11:08 SvenBudak

Hello, we are also looking forward to this feature. The experimental version is working almost correctly for us with but 2 flaws:

  1. When initially loading a virtual scroll with many elements, but 2 rows stretching across the entire view area, more than two rows are loaded until you scroll to the last element.
  2. After scrolling to the last element, it is impossible to scroll all the way back up. The view is cut off.

Frotty avatar Aug 19 '19 14:08 Frotty

@mmalerba any news?

cesco69 avatar Aug 27 '19 16:08 cesco69

We need this feature. Still waiting for it. :smile_cat:

prashanthc avatar Sep 09 '19 13:09 prashanthc

It seems to be working fine in most of the time, except that there is always an empty space on the bottom that keeps increasing in size each time you scroll down and up a bit.

Facing the same issue

sufiiiyan avatar Sep 18 '19 09:09 sufiiiyan

Any update on this? Particularly the re-introduction of the scrolledIndexChange event with variable height items. Unless anyone knows of a work-around to be able to identify when the bottom of the list has been scrolled to, so that I know to fetch more data from the back-end?

Did you resolve it?

jaigtz88 avatar Oct 01 '19 10:10 jaigtz88

This is such a cool feature, any plans on releasing it to production yet?

jsachica avatar Oct 01 '19 14:10 jsachica

This is such a cool feature, any plans on releasing it to production yet?

For that it would need to work properly, I suppose.

Frotty avatar Oct 01 '19 14:10 Frotty

Cant release my image board before this feature is done ;P

SvenBudak avatar Oct 01 '19 19:10 SvenBudak

As of now is there any way to have responsive list design along with virtual scroll?

I'm using Angular Flex Layout along with virtual scroll, so I believe we can be aware of what will be the size of items on any specific screen size, but can we bind itemSize property to populate it dynamically,

it won't be essentially updated once assigned apart from probably when orientation changes on Tabs or cellular devices.

saif003 avatar Oct 02 '19 05:10 saif003

someone got a good working service to calculate (without to much lost of performance) the hight of items?

SvenBudak avatar Oct 19 '19 23:10 SvenBudak

Scrolling down with autosize directive is working fine but while scrolling up its jumping to the start of the list.

tibinthomas avatar Nov 01 '19 09:11 tibinthomas

Anyone in the world other than me worrying about this? Is this issue a solvable or can we solve it by proving it can't be solved?

tibinthomas avatar Nov 04 '19 08:11 tibinthomas

@SvenBudak @tibinthomas what I did to solve that issue instead of scrolling directly to the selected element I scroll element by it's height height to the top or bottom, check if element I look for is visible, if not scroll again until element is found. It's not perfect but it works in most situations.

yadue avatar Nov 04 '19 11:11 yadue

@mmalerba said they would get back to this after vacation, but seems like they are working on other things now :/

Frotty avatar Nov 04 '19 17:11 Frotty

Yes, supporting Ivy and creating new Test Harnesses has taken priority over this work. This is still a high priority issue that the team intends to address.

Splaktar avatar Nov 14 '19 22:11 Splaktar

any news when this is going to be released?

cdk-virtual-scroll-viewport makes no sense to me with a fixed height.

noobcoder15 avatar Dec 29 '19 22:12 noobcoder15

the most important thing is that those inner items must be of fixed height

Is this thread not virtual scroll, for items of unknown size?

alexbjorlig avatar Jan 21 '20 20:01 alexbjorlig

any update on this? My user case needs various size of rows. Using the fixed size virtual-scroll has a lot of jumping issues, but the auto-sized one is still not production ready?

samyue avatar Mar 05 '20 23:03 samyue

It's not. I wouldn't hold my breath. This library supports varying row height with a cache: https://github.com/rintoj/ngx-virtual-scroller

Frotty avatar Mar 06 '20 00:03 Frotty

in autosize, scroll down event working fine while scrolling up facing jump issue when scrolling gets to stop. any update for the same?

thackerronak avatar Mar 07 '20 10:03 thackerronak

Here's a brute approach to a very annoying missing functionality that nobody from the angular team seems to care about.


interface RowInfo {
    height: number
    id: string
}

export class CustomVirtualScrollStrategy implements VirtualScrollStrategy {

    private viewport:CdkVirtualScrollViewport;
    private rowSizeCache = new Map<string, RowInfo>();
    private orderedItemIds:string[] = [];
    scrolledIndexChange = new Subject<number>();
    attachedSubject = new Subject<CdkVirtualScrollViewport>();


    constructor(private minItemHeight:number=48, private renderItemsBefore=2, private renderItemsAfter=2) {
    }

    onContentRendered(): void {
    }

    attach(viewport: CdkVirtualScrollViewport): void {
        if(viewport == this.viewport){
            return
        }
        this.attachedSubject.next(viewport);
        this.viewport = viewport;

        const changeObserver = new Observable<HTMLElement>(subscriber => {

            const watchedEl = viewport.elementRef.nativeElement.firstChild as HTMLElement;

            const mutationObserver = new MutationObserver(() => {
                subscriber.next(watchedEl)
            });

            mutationObserver.observe(viewport.elementRef.nativeElement.firstChild, {
                attributes: true,
                //characterData: true,
                childList: true,
                subtree: true,
                attributeOldValue: true,
                //characterDataOldValue: true
            });

           return () => {
               mutationObserver.disconnect();
           }
        });

        changeObserver.pipe(
            debounceTime(100),
            takeUntil(this.attachedSubject)
        ).subscribe(rootEl => {
            let changed = false;
            // each child of cdk-virtual-scroll-viewport should have data-row-id and data-row-index attributes defined
            // <div *cdkVirtualFor="let row of dataSource.onData() | async; let index = index;" [attr.data-row-id]="row.getId()" [attr.data-row-index]="index">
            const list = Array.from(rootEl.querySelectorAll("[data-row-id][data-row-index]")) as HTMLElement[];

           

            for(const el of list){
                const id = el.getAttribute('data-row-id');
                const idx = parseInt(el.getAttribute('data-row-index'), 10);
                let rowInfo = this.rowSizeCache.get(id);
                if(!rowInfo){
                    rowInfo = {height:0, id: id};
                    this.rowSizeCache.set(id, rowInfo)
                }

                const clientHeight = el.clientHeight;

                if(rowInfo.height != clientHeight){
                    rowInfo.height = clientHeight;
                    changed = true
                }

                if(!isNaN(idx)){
                    this.orderedItemIds[idx] = id;
                }
            }

            if(changed){
                this.updateTotalContentSize();
                this.updateRenderedRange()
            }

        })

    }

    private updateRenderedRange() {
        if (!this.viewport) {
            return;
        }

        // TODO handle item removal
        // TODO handle reordering items
        // TODO various other optimizations can be performed as we don't always need to check each row height

        const scrollOffset = this.viewport.measureScrollOffset();
        const viewportSize = this.viewport.getViewportSize();
        const maxOffset = scrollOffset+viewportSize;
        const maxLastVisibleIndex = Math.ceil(maxOffset / this.minItemHeight);

        const dataLength = this.viewport.getDataLength();

        let offset = 0;
        const visibleRange = {startIndex:NaN, endIndex:NaN, startOffset:0, endOffset:0}; // contains rows which are partially or fully visible
        for(let i=0;i < Math.min(dataLength, maxLastVisibleIndex); i++){

            let itemHeight = this.minItemHeight;
            const itemId = this.orderedItemIds[i];
            if(itemId){
                itemHeight = this.rowSizeCache.get(itemId).height
            }

            if(offset > maxOffset){
                break;
            }

            if(offset+itemHeight >= scrollOffset){
                if(isNaN(visibleRange.startIndex)){
                    visibleRange.startIndex = i;
                    visibleRange.startOffset = offset;
                }

                visibleRange.endIndex = i;
                visibleRange.endOffset = offset + itemHeight;
            }

            offset += itemHeight;

        }

        const firstVisibleIndex = visibleRange.startIndex;

        for(let i=this.renderItemsBefore; i>0 && visibleRange.startIndex > 0; i-=1){
            visibleRange.startIndex -= 1;
            visibleRange.startOffset -= this.getItemHeight(visibleRange.startIndex)
        }

        for(let i=this.renderItemsAfter; i>0 && visibleRange.endIndex < dataLength-1; i-=1){
            visibleRange.endIndex += 1;
            visibleRange.endOffset += this.getItemHeight(visibleRange.endIndex)
        }

        this.viewport.setRenderedRange({start:visibleRange.startIndex, end: visibleRange.endIndex+1});
        this.viewport.setRenderedContentOffset(visibleRange.startOffset);
        this.scrolledIndexChange.next(firstVisibleIndex);
    }

    private updateTotalContentSize() {
        if (!this.viewport) {
            return;
        }

        let totalHeight = 0;

        for(let i=0; i< this.viewport.getDataLength(); i++){
            totalHeight += this.getItemHeight(i);
        }

        this.viewport.setTotalContentSize(totalHeight);
    }

    private getItemHeight(index: number): number{
        const itemId = this.orderedItemIds[index];
        if(itemId){
            return this.rowSizeCache.get(itemId).height
        }
        return this.minItemHeight;
    }


    detach(): void {
        if(this.viewport){
            this.viewport = null;
            this.attachedSubject.next(null)
        }
    }

    onContentScrolled(): void {
        this.updateRenderedRange();
    }

    onDataLengthChanged(): void {
        this.updateTotalContentSize();
        this.updateRenderedRange();
    }

    onRenderedOffsetChanged(): void {
    }

    scrollToIndex(index: number, behavior: "auto" | "smooth"): void {
        //TODO
    }


}

jocker avatar Mar 10 '20 15:03 jocker

Working Example

feed.component.html

 <cdk-virtual-scroll-viewport
        #viewport class="example-viewport" 
[style.height.px]="getHeight"  <!-- calc(100vh)  -->
 autosize fxFlex>
                    <div  #listComponent  fxFlex fxLayout="column" *ngIf="messages && messages.length > 0">
                        <div
                             *cdkVirtualFor="let item of messages;let index = index; templateCacheSize: 0;
                                trackBy: indexTrackFn; let i = index"
                                  class="feed-messages"  [style.height.px]="item">
                            <app-message *ngIf="item?.senderId"
                                         [messageInput]="item"
                                         [messageUser]="chatUsers.users[item.senderId]"
                            ></app-message>
                        </div>
                    </div>
                </cdk-virtual-scroll-viewport>

feed.component.ts

export class FeedComponent implements OnInit, AfterViewInit , OnDestroy {
  @ViewChild(CdkVirtualScrollViewport, {static: true}) viewport: CdkVirtualScrollViewport;
  @Input('isPageLoaded') set setIsPageLoaded(isPageLoaded) {
    if (isPageLoaded) {
      (<any>this.viewport).checkViewportSize();
      console.log('isPageLoaded', isPageLoaded);
    }
  };
ngOnInit(): void {
    fromEvent(window, 'resize')
      .pipe(
        distinctUntilChanged(),
        debounceTime(10),
        takeUntil(this.deactivatedSubject)
      ).subscribe(() => {
           (<any>this.viewport).checkViewportSize();

    });
    this.viewport.elementScrolled().subscribe(() => {
      console.log(this.viewport.getRenderedRange()) //{start: 4, end: 19}
    })
  }

}

dudipsh avatar Apr 01 '20 08:04 dudipsh

@dudipsh Can you share online example?

I'm trying with 9.2.0 version and receiving error message:

ERROR Error: "Error: cdk-virtual-scroll-viewport requires the "itemSize" property to be set."

arkadiusz-wieczorek avatar Apr 03 '20 13:04 arkadiusz-wieczorek

@arkadiusz-wieczorek

did you import the ScrollingModule from cdk-experimental?

import { ScrollingModule } from '@angular/cdk/scrolling';
import { ScrollingModule as ExperimentalScrollingModule} from '@angular/cdk-experimental/scrolling';

@NgModule({
  declarations: [
  ],
  imports: [
    ScrollingModule,
    ExperimentalScrollingModule,
  ]
})
export class FeedModule { }

dudipsh avatar Apr 03 '20 16:04 dudipsh

thanks @dudipsh, my fault!

arkadiusz-wieczorek avatar Apr 06 '20 06:04 arkadiusz-wieczorek

Looking at using an expander in virtual scroll ie a click a button and an item height expands to contain a sub-menu, which can vary per item.

Tried using the the autosize, but didn't seem to work quite right.

Is the plan for this this be able to also support this?

pjc2007 avatar May 10 '20 02:05 pjc2007

Autosize works but there are other features missing then. For example scrolledIndexChange is not working. But I really need to know which element is at the top.

ewalddieser avatar May 10 '20 18:05 ewalddieser

Autosize works but there are other features missing then. For example scrolledIndexChange is not working. But I really need to know which element is at the top.

Have you tried to use the viewport to get that information? using the this.viewport.getRenderedRange()

see the example : https://github.com/angular/components/issues/10113#issuecomment-607102447

buenjybar avatar Jun 10 '20 11:06 buenjybar

@buenjybar

    ngOnInit(): void {
        this.route.paramMap.subscribe((res) => {
            this.activeChannel = res.get('id');
            this.chatService.readMessagesInChannel(this.activeChannel, 0, 40).subscribe((channelData: any) => {
                this.messages = channelData.data.reverse().map((item, index) => {
                    this.scrollTo(index * 299, 'auto');
                    return item;
                });
                this.startIndex = channelData.totalCount;
            });
        });

        this.viewport.elementScrolled()
            .pipe(debounceTime(150))
            .subscribe((res) => {
                const {start, end} = this.viewport.getRenderedRange();
                if (start === 0) {
                    this.fetchMore();
                }
            });

    }

    scrollTo(size, behavior: 'auto' | 'smooth' = 'auto') {
        setTimeout(() => {
            this.viewport.elementRef.nativeElement.scrollTo({top: size, behavior, left: 0});
        }, 300);
    }

dudipsh avatar Jun 14 '20 16:06 dudipsh

Autosize works but there are other features missing then. For example scrolledIndexChange is not working. But I really need to know which element is at the top.

Have you tried to use the viewport to get that information? using the this.viewport.getRenderedRange()

see the example : #10113 (comment)

Yes, sure with some hack you can make it work. It still would be nice if the API that the components provide would work no matter if item size is fixed or dynamic. I mean the (scrolledIndexChange) output.

ewalddieser avatar Jun 15 '20 07:06 ewalddieser

@ewalddieser

I usually agree with this approach But this issue opened from 2018, it looks like it's time for "hacks"

By the way Denis Hilt works on a solution for a chat experience virtual scroll that starts from the bottom with auto height its in progress but its looks like a very good solution https://github.com/dhilt/ngx-ui-scroll

working example https://stackblitz.com/edit/ngx-ui-scroll-chat-app

dudipsh avatar Jun 15 '20 08:06 dudipsh

When it will be released?

teland94 avatar Sep 06 '20 00:09 teland94

@dudipsh Can you share online example?

I'm trying with 9.2.0 version and receiving error message:

ERROR Error: "Error: cdk-virtual-scroll-viewport requires the "itemSize" property to be set."

@arkadiusz-wieczorek I moved to this package https://github.com/dhilt/ngx-ui-scroll no issues... work perfectly

dudipsh avatar Sep 06 '20 09:09 dudipsh

I am looking forward to this feature too

ahnpnl avatar Oct 05 '20 13:10 ahnpnl

'cdk-virtual-scroll-spacer' is not taking height beyond 22339600px, that means user can not scroll down further if list showing in virtual table is beyond 22339600px height. example: i have log viewer with millions of records, cdk-virtual-scroll-spacer height is calculated based on itemSize * numberOfItems. to show 2 millions of records with 20px row height need 40million px cdk-virtual-scroll-spacer height, but chrome is limiting cdk-virtual-scroll-spacer height to 22339600px. how do we overcome this limit ?

vraddy avatar Oct 28 '20 09:10 vraddy

@vraddy this has nothing to do with this ticket. Also if you think scrolling through 2 million entries is feasible, reconsider your design choices (i.e. truncate your data).

Frotty avatar Oct 28 '20 23:10 Frotty

any news about this ticket?

SvenBudak avatar Nov 21 '20 05:11 SvenBudak

Any progress for this issue?

Celend avatar Dec 02 '20 09:12 Celend

ngx-virtual-scroller lib is best for unknown size just used it till any next update. https://github.com/rintoj/ngx-virtual-scroller/

thackerronak avatar Dec 02 '20 10:12 thackerronak

@thackerronak its not really working. the guy who created this one is not available for accepting merge requests and he also cant update the npm package. My team was testing community updates from ngx-virtual-scroller but its not working well. alot bugs and problems.

We have to wait for cdk solution. The Ionic Team wrote anything about that ion-virtual-scroll will switch to cdk. maybe ionic team is working together with the angular team on this problem. we wait already 4 years. I am not sure that this fix will come any day... i have already 4 apps they are ready to release if this cdk fix is out. i worked last 5 years on them... i just hope it will come...

SvenBudak avatar Dec 02 '20 10:12 SvenBudak

Does https://github.com/rintoj/ngx-virtual-scroller/ work with tables that have sticky headers?

Mmatiasn avatar Dec 11 '20 01:12 Mmatiasn

@Mmatiasn i used "ngx-virtual-scroller" ( for NPM package ) you can try to fork and implement sticky headers https://github.com/dudipsh/ngx-ui-table

dudipsh avatar Dec 11 '20 08:12 dudipsh

If anyone has stumbled across the requirement for items of different, but known size (a mixture between the fixed and autosize scrolling strategies) - I've elaborated more in this SO question.

milanov avatar Feb 13 '21 18:02 milanov

Sad to say, but the performance is much worse comparing to the fixed scrolling strategy.

ms-dosx86 avatar Feb 17 '21 07:02 ms-dosx86

dont wait for a solution. add meanwhile a intersection observer which detechts that the user reach the end of the list and load then the next X entries. This is how we did it for now. I dont think that we will get for the web a good working virtual scroll. It seems that this is a feature that works only well in native java i think.

SvenBudak avatar May 14 '21 22:05 SvenBudak

Yeah, I'm not really waiting for it, In the end I managed to use multiple workarounds for my usecases but it just amazes me the long time this issue has been around. Btw this one works great: https://github.com/rintoj/ngx-virtual-scroller/

xjuanc avatar May 14 '21 23:05 xjuanc

This package also has its problems. Just like many others. After almost 2 years we have accepted that there is simply no "perfect" solution written in JS.

SvenBudak avatar May 15 '21 03:05 SvenBudak

Hi Angular team. Picking up from https://github.com/angular/components/issues/10113#issuecomment-778660378 (creating a strategy for scrolling items with different, but fixed sizes). I've modified the code suggested in the SO question and it seems to work. The usage is very close to the existing strategy: <cdk-virtual-scroll-viewport [itemSizes]='myDataSource.heights'>.

  1. Do you think the use case is generic enough so that i try to create a PR in the experimental cdk, and eventually this becomes an official virtual scrolling strategy? If not, it can be published as a standalone npm module.
  2. Is there a set of tests that are meant for different scrolling strategies, something like acceptance tests that cover basic functionality? I attempted to reuse the ones for the fixed strategy, but they also include template cache/track by/etc tests.

milanov avatar Jun 14 '21 07:06 milanov

Why all its github github youre think github is verry good?

On Mon, 14 Jun 2021, 3:55 pm Milan Milanov, @.***> wrote:

Hi Angular team. Picking up from #10113 (comment) https://github.com/angular/components/issues/10113#issuecomment-778660378 (creating a strategy for scrolling items with different, but fixed sizes). I've modified the code suggested in the SO question and it seems to work. The usage is very close to the existing strategy: <cdk-virtual-scroll-viewport [itemSizes]='worklistItemsDataSource.heights'>.

  1. Do you think the use case is generic enough so that i try to create a PR in the experimental cdk, and eventually this becomes an official virtual scrolling strategy? If not, it can be published as a standalone npm module.
  2. Is there a set of tests that are meant for different scrolling strategies, something like acceptance tests that cover basic functionality? I attempted to reuse the ones for the fixed strategy https://github.com/angular/components/blob/master/src/cdk/scrolling/virtual-scroll-viewport.spec.ts#L32, but they also include template cache/track by/etc tests.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/angular/components/issues/10113#issuecomment-860469374, or unsubscribe https://github.com/notifications/unsubscribe-auth/AS255R6GXVK44VIMALYKC33TSWYVRANCNFSM4ESGGQYQ .

Asiabi avatar Jun 14 '21 08:06 Asiabi

@milanov the full strategy (includes viewport resize, which I decided to omit) I've adapted the SO answer from is covered with unit tests, so it's definitely possible. If you wish to create a module based on it, that'd be awesome, I would have used it instead of rolling out a custom strategy.

Klaster1 avatar Jun 14 '21 17:06 Klaster1

@milanov Rather than taking an array input like in the SO question, I think a function would be a more flexible API, e.g.:

HTML:

<cdk-virtual-scroll-viewport customVirtualScrollStrategy [itemSize]="itemSizeFn">

TS:

itemSizeFn = (item, index) => index % 2 ? 50 : 100;

I don't think we separate out the tests that are common to all scrolling strategies. I would just use the fixed size strategy tests as a template and remove ones that aren't relevant to your strategy

mmalerba avatar Jun 14 '21 23:06 mmalerba

Thanks for the quick responses. Some followups for @mmalerba:

  • I’m still not sure if I should attempt to create a PR in the experimental cdk repository, or publish the strategy separately
  • (depending on the above) Would you expect the new strategy to have the same API as the current ones do (min/maxBufferPx). The implementation right now supports what number of elements are to be rendered before/after the visible part of the scroll (lets say 3 elements), which makes the calculations much simpler.
  • I don't think we can have an itemSizeFn with a signature of (item, index), as we don’t actually have access to the items in the scrolling strategy, but index alone would be doable

As for @Klaster1 , can you elaborate on the viewport resize part? I actually modified your code to be as close as possible to the fixed size strategy (in terms of code structure), and it seems there isn't anything missing, simply the calculations in the _updateRenderedRange are different.

milanov avatar Jun 15 '21 18:06 milanov

I think we can make some kind of change to this repository, I just want to make sure we settle on a good API first. That makes sense about itemSizeFn, I figured there was a reason I didn't implement it already, and its probably because its not really possible without some big refactoring. What if for now we change the itemSize to take number | number[] instead of just number. That way we don't need to add a new strategy, we could just expand the current one.

Also, I think rather than making the user enumerate all the heights, it would be nice to accept an array like [10, 100] which would result in alternating heights of 10 and 100 for all of the items. (As opposed to what's shown in the stackblitz example you linked to, where it uses an array of 500 sizes to accomplish the same thing: Array.from(Array(500).keys()).map(i => (i % 2 ? 50 : 100))

mmalerba avatar Jun 15 '21 19:06 mmalerba

A assume different people will have different use-cases, so lets hear opinions from the community about the API. From my perspective, @mmalerba, the way to go would be:

  • Introduce a new virtual scrolling strategy with an itemSizeFn parameter, taking the index of a given element and returning its height. This new strategy will be in cdk-experimental and would render a predefined number of items before/after the currently visible viewport.
  • (Release and take feedback from the community)
  • Add minBufferPx and maxBufferPx. This will not be a breaking change and will align this strategy with the currently existing ones.
  • (Release and take feedback from the community)
  • (Optional) Merge the two strategies into one that takes either itemSize or itemSizeFn, thus eliminating duplication of code/tests. This should be done only if the differences in the calculations can be properly isolated.

As a side note, I'm not a fan of the minBufferPx and maxBufferPx idea, I find it simpler to reason about the behaviour in terms of how much items should be rendered before/after the viewport. However, I assume that this API is here to stay, and therefore the suggestion above.

milanov avatar Jun 21 '21 12:06 milanov

Could someone explain me what was wrong with jocker's brute force implementation posted earlier in this thread? Was it downvoted because of performance issues, maintainability issues, security issues, or something else?

I am asking because I also need to support a list of items of variable item size, which is very different from milanov's requirement (of different, but fixed sizes). And jocker's solution while not very elegant, gets the job done.

So far the only working solution which also supports at the end of the day the scrollToIndex API was posted by jocker I think. So I am curious what's the main reason for the downvotes.

zergeborg avatar Jun 25 '21 02:06 zergeborg

@milanov I only have a very subjective, but probably relevant feedback. It would be really nice if the name of the strategy would highlight the fact that the strategy is not an auto-size strategy. Just off the top of my head StaticVariableSizeScrollStrategy or ProgrammaticVariableSizeScrollStrategy comes to my mind as opposed to e.g. a dynamic auto size strategy.

zergeborg avatar Jun 25 '21 02:06 zergeborg

@zergeborg Thanks for the feedback. With regards to naming, right now I'm leaning towards FixedSizesVirtualScrollStrategy (with the s in sizes). What I'm suggesting will not work for your case, but I'm hoping it might work for others. The three strategies (fixed size, multiple fixed sizes, dynamic size) should be complementary to each other.

milanov avatar Jun 25 '21 06:06 milanov

It looks like autosize is included in @angular/cdk-experimental. I noticed the paragraph under the example here https://material.angular.io/cdk/scrolling/overview#scrolling-over-fixed-size-items

nathanaelmayne avatar Jul 19 '21 23:07 nathanaelmayne

Is there any ETA for when cdk-experimental will be stable?

Specifically:

ERROR Error: cdk-virtual-scroll: scrolledIndexChange is currently not supported for the autosize scroll strategy

Also, elements seem to jump around a bit when adding additional entries.

ciriousjoker avatar Sep 15 '21 17:09 ciriousjoker

"@angular/cdk": "12.2.8", "@angular/cdk-experimental": "12.2.8"

If i have set only autosize, i get an error Error: cdk-virtual-scroll-viewport requires the "itemSize" property to be set.

juri33 avatar Oct 06 '21 06:10 juri33

Is this feature ever going to be implemented?

tobiasmuecksch avatar Apr 18 '22 18:04 tobiasmuecksch

Any update on this? Is this not being considered anymore?

asifnkhan avatar Jul 15 '22 08:07 asifnkhan