Closed ghenry22 closed 2 months ago
Do you have a reproducible example of this behavior? The library renders the first element in the list in order to calculate the item width and height, so no matter how complex the component is it should be able to calculate its size.
However, if your component is waiting for a network request or other async event to finish before displaying its content, then the calculation will be incorrect since the virtual scroll component will record the size of the item as soon as the item is rendered. If this is your use-case, I can look into adding a itemCalcDelay
property that would take in an Observable
to wait for before beginning the calculation.
It’s just an ionic ion-item with a thumbnail image and a few lines of text. No http requests or anything going on.
I found that a simple div would work but the ionic component would only render the first item.
when I explicitly set the itemHeight then everything renders as expected.
I have an issue wich is maybe related.
<li-virtual-scroll [items]="pagesToShow"
[itemHeight]="365"
[itemWidth]="244". <---- This causes that there's just one element rendered
[viewCache]="100"
>
<rw-page-image
*liVirtualItem="let page"...
When i don't set the itemWidth then all items are rendered.
Using another config
<li-virtual-scroll [items]="pagesToShow"
[itemHeight]="436"
[viewCache]="100"
[bufferLength]="30"
[eventCapture]="true"
[gridList]="true"
[asyncRendering]="true"
>
<rw-page-image
*liVirtualItem="let page"
Renders into a representation of the list super fast (amazing) but it does not append further items when i scroll to the end
Same issue happening for me when using the material grid list. Only the first one is being rendered
<mat-grid-list cols="4" rowHeight="1:1" gutterSize="15px">
<li-virtual-scroll [items]="selectedPack.stickers || []" [gridList]="true">
<mat-grid-tile (click)="selectSticker(sticker)" *liVirtualItem="let sticker">
@if(!images[sticker.name]){<mat-icon>pending</mat-icon>}
@if(images[sticker.name] == ImageLoadStatus.ERROR){<mat-icon>error</mat-icon>}
@if(images[sticker.name] != ImageLoadStatus.ERROR){
<img #img
[style.display]="images[sticker.name] == ImageLoadStatus.LOADED ? 'block' : 'none'"
(load)="images[sticker.name] = ImageLoadStatus.LOADED; img.style.opacity = '1'"
(error)="images[sticker.name] = ImageLoadStatus.ERROR"
class="grid-sticker pointer fade-img"
[src]="uriFromSticker(sticker)"/>
}
</mat-grid-tile>
</li-virtual-scroll>
</mat-grid-list>
Same issue happening for me when using the material grid list. Only the first one is being rendered
<mat-grid-list cols="4" rowHeight="1:1" gutterSize="15px"> <li-virtual-scroll [items]="selectedPack.stickers || []" [gridList]="true"> <mat-grid-tile (click)="selectSticker(sticker)" *liVirtualItem="let sticker"> @if(!images[sticker.name]){<mat-icon>pending</mat-icon>} @if(images[sticker.name] == ImageLoadStatus.ERROR){<mat-icon>error</mat-icon>} @if(images[sticker.name] != ImageLoadStatus.ERROR){ <img #img [style.display]="images[sticker.name] == ImageLoadStatus.LOADED ? 'block' : 'none'" (load)="images[sticker.name] = ImageLoadStatus.LOADED; img.style.opacity = '1'" (error)="images[sticker.name] = ImageLoadStatus.ERROR" class="grid-sticker pointer fade-img" [src]="uriFromSticker(sticker)"/> } </mat-grid-tile> </li-virtual-scroll> </mat-grid-list>
For grid, your li-virtual-scroll parent item needs to have an explicit height AND width set (ie height: 100%, width 100%)
Your items that will be rendered in the grid ALSO need to have a width and height set.
There is also a bit of CSS needed, check out the demo repo and have a look at the CSS there for the scroll-container item which has sub items for list-items with different CSS when grid is true or false on the li-virtual-scroll element.
You can see all this in the demo, but they are not automatically applied it seems when just using the library. Could probably be incorporated into the README.MD to make it clearer.
I just spent an afternoon working through these scenarios again to get list/grid virtualscrolls working.
Looks really good now that I have all the bits together and both list and grid render and scroll nicely.
Without this I found that the grid just rendered a list.
I have an issue wich is maybe related.
<li-virtual-scroll [items]="pagesToShow" [itemHeight]="365" [itemWidth]="244". <---- This causes that there's just one element rendered [viewCache]="100" > <rw-page-image *liVirtualItem="let page"...
When i don't set the itemWidth then all items are rendered.
Using another config
<li-virtual-scroll [items]="pagesToShow" [itemHeight]="436" [viewCache]="100" [bufferLength]="30" [eventCapture]="true" [gridList]="true" [asyncRendering]="true" > <rw-page-image *liVirtualItem="let page"
Renders into a representation of the list super fast (amazing) but it does not append further items when i scroll to the end
When you see all the items in the DOM like that you are not actually getting virtual scrolling. Have a read of my previous comments. You need the parent element to have an explicitly set height and for grid mode also width. Otherwise the virtual list assumes that the viewport size is infinite and just renders everything resulting in no virtual scroll.
When it's working you can open the dev tools and you will see a shorter list of virtual items and you will see them flash up as they are recycled through the view while you scroll.
Check the demo repo as it has some good examples of some of the extra bits of CSS that are needed to make everything play nice.
I'm going to close this because if you read through the comments you can see the cause and the fix.
The parent element must have a defined width and height (ie height: 100vh; width: 100vw; to use the entire available space).
When gridEnabled = false, you MUST specify the item height and it must be close to the actual height.
When gridEnabled = true, you MUST specify the item height and the item width and it must be close to the actual height and width.
When these set you will see both proper virtual scrolling when you check the DOM (ie elements moved in and out when you scroll) and all items displaying as expected.
There are some other bits of CSS that are useful for getting the desire behaviour and you can check these out in the demo repo and largely copy and paste then edit down to just what you need.
@ghenry22 Thanks for troubleshooting this. I'll update the README to make these limitations clear.
Edit: The README has been updated to clarify item sizing requirements.
If [itemHeight] is not set and the item is a basic DIV then the list renders as expected.
If [itemHeight] is not set and the item is a complex component then the list renders only a single item (that 1 item renders perfectly fine)
If [itemHeight] is set then both scenarios work.
Proposed Solutions 1) Ideally auto determine height of items even when complex components are in use. 2) Update the docs to explain this behaviour and make the requirement to set [itemHeight] clear.