import { CdkFixedSizeVirtualScroll, FixedSizeVirtualScrollStrategy, VIRTUAL_SCROLL_STRATEGY, } from "@angular/cdk/scrolling"; import { Directive, forwardRef } from "@angular/core"; // Custom virtual scroll strategy for cdk-virtual-scroll // Uses a sample list item to set the itemSize for FixedSizeVirtualScrollStrategy // The use case is the same as FixedSizeVirtualScrollStrategy, but it avoids locking in pixel sizes in the template. export class CipherListVirtualScrollStrategy extends FixedSizeVirtualScrollStrategy { private checkItemSizeCallback: any; private timeout: any; constructor( itemSize: number, minBufferPx: number, maxBufferPx: number, checkItemSizeCallback: any ) { super(itemSize, minBufferPx, maxBufferPx); this.checkItemSizeCallback = checkItemSizeCallback; } onContentRendered() { if (this.timeout != null) { clearTimeout(this.timeout); } this.timeout = setTimeout(this.checkItemSizeCallback, 500); } } export function _cipherListVirtualScrollStrategyFactory(cipherListDir: CipherListVirtualScroll) { return cipherListDir._scrollStrategy; } @Directive({ selector: "cdk-virtual-scroll-viewport[itemSize]", providers: [ { provide: VIRTUAL_SCROLL_STRATEGY, useFactory: _cipherListVirtualScrollStrategyFactory, deps: [forwardRef(() => CipherListVirtualScroll)], }, ], }) export class CipherListVirtualScroll extends CdkFixedSizeVirtualScroll { _scrollStrategy: CipherListVirtualScrollStrategy; constructor() { super(); this._scrollStrategy = new CipherListVirtualScrollStrategy( this.itemSize, this.minBufferPx, this.maxBufferPx, this.checkAndUpdateItemSize ); } checkAndUpdateItemSize = () => { const sampleItem = document.querySelector( "cdk-virtual-scroll-viewport .virtual-scroll-item" ) as HTMLElement; const newItemSize = sampleItem?.offsetHeight; if (newItemSize != null && newItemSize !== this.itemSize) { this.itemSize = newItemSize; this._scrollStrategy.updateItemAndBufferSize( this.itemSize, this.minBufferPx, this.maxBufferPx ); } }; }