I am working on a project where I need to implement a virtual scrolling component in Angular without using any third-party libraries. I found this article about building a virtual scroll in React(https://dev.to/adamklein/build-your-own-virtual-scroll-part-i-11ib), but I am unable to understand how the itemsToDisplay array works in this context. It suppose to load items that fit within the viewport only once and there will not be a scroll bar to scroll after that.
I am new to angular and I'm not sure if there is something I'm missing. Can anyone help me with this issue. Thanks in advance.
The source is as follows.
virtual-scroller.component.ts
import {
Component,
Input,
Output,
EventEmitter,
ViewChild,
ElementRef,
AfterViewInit,
} from '@angular/core';
@Component({
selector: 'app-virtual-scroller',
templateUrl: './virtual-scroller.component.html',
styleUrls: ['./virtual-scroller.component.css'],
})
export class VirtualScrollerComponent implements AfterViewInit {
@Input()
items: any[] = [];
@Output() scrollEnd = new EventEmitter();
@ViewChild('container')
container!: ElementRef;
height = '100px';
itemsToDisplay: any[] = [];
ngAfterViewInit() {
setTimeout(() => {
this.loadItems();
}, 0);
}
loadItems() {
const viewportHeight = this.container.nativeElement.offsetHeight;
const itemHeight = 50;
const itemsPerViewport = Math.ceil(viewportHeight / itemHeight);
this.itemsToDisplay = this.items.slice(0, itemsPerViewport);
}
onScroll(event: any) {
const viewportHeight = this.container.nativeElement.offsetHeight;
const scrollHeight = this.container.nativeElement.scrollHeight;
const scrollTop = this.container.nativeElement.scrollTop;
const itemHeight = 50;
const itemsPerViewport = Math.ceil(viewportHeight / itemHeight);
if (scrollTop + viewportHeight >= scrollHeight) {
this.scrollEnd.emit();
} else {
const firstVisibleIndex = Math.floor(scrollTop / itemHeight);
this.itemsToDisplay = this.items.slice(
firstVisibleIndex,
firstVisibleIndex + itemsPerViewport
);
}
}
}
virtual-scroller.component.html
<div #container [style.height]="height" [style.overflow-y]="'scroll'" (scroll)="onScroll($event)">
<div *ngFor="let item of itemsToDisplay">
{{ item.name }}
</div>
</div>
** home.component.ts**
import {
Component,
ElementRef,
EventEmitter,
Input,
OnInit,
Output,
ViewChild,
} from '@angular/core';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css'],
})
export class HomeComponent implements OnInit {
ngOnInit(): void {}
items: any[] = [
{ name: 'Gayan' },
{ name: 'Sahan' },
{ name: 'Buddhika' },
{ name: 'Nuwan' },
{ name: 'Isuru' },
{ name: 'Naleen' },
{ name: 'Asanka' },
];
}
home.component.html
<app-virtual-scroller [items]="items">