Virtual scroll
ng-select can render large lists efficiently by enabling [virtualScroll]="true", which only renders the options currently visible in the dropdown viewport.
Virtual scroll
Section titled “Virtual scroll”import { Component, OnInit, inject, ChangeDetectionStrategy } from '@angular/core';import { HttpClient } from '@angular/common/http';
import { NgHeaderTemplateDirective, NgOptionTemplateDirective, NgSelectComponent } from '@ng-select/ng-select';
@Component({ selector: 'ng-virtual-scroll-example', templateUrl: './virtual-scroll-example.component.html', styleUrls: ['./virtual-scroll-example.component.scss'], changeDetection: ChangeDetectionStrategy.Eager, imports: [NgSelectComponent, NgHeaderTemplateDirective, NgOptionTemplateDirective],})export class VirtualScrollExampleComponent implements OnInit { private http = inject(HttpClient);
photos = []; photosBuffer = []; bufferSize = 50; numberOfItemsFromEndBeforeFetchingMore = 10; loading = false;
ngOnInit() { this.http.get<any[]>('https://jsonplaceholder.typicode.com/photos').subscribe((photos) => { this.photos = photos; this.photosBuffer = this.photos.slice(0, this.bufferSize); }); }
onScrollToEnd() { this.fetchMore(); }
onScroll({ end }) { if (this.loading || this.photos.length <= this.photosBuffer.length) { return; }
if (end + this.numberOfItemsFromEndBeforeFetchingMore >= this.photosBuffer.length) { this.fetchMore(); } }
private fetchMore() { const len = this.photosBuffer.length; const more = this.photos.slice(len, this.bufferSize + len); this.loading = true; // using timeout here to simulate backend API delay setTimeout(() => { this.loading = false; this.photosBuffer = this.photosBuffer.concat(more); }, 200); }}<p>In this example we are loading many items but only ~30 of them are rendered in the DOM. This allows to load as big data as you want.</p>
<ng-select [items]="photosBuffer" [virtualScroll]="true" [loading]="loading" bindLabel="title" bindValue="thumbnailUrl" placeholder="Select photo" (scroll)="onScroll($event)" (scrollToEnd)="onScrollToEnd()"> <ng-template ng-header-tmp> <small class="form-text text-muted">Loaded {{ photosBuffer.length }} of {{ photos.length }}</small> </ng-template> <ng-template ng-option-tmp let-item="item" let-index="index"> <b>{{ index }}</b> {{ item.title }} </ng-template></ng-select>Inputs used by the examples on this page:
| Input | Type | Default | Description |
|---|---|---|---|
| [virtualScroll] | boolean |
false | Enable virtual scroll for better performance when rendering a lot of data |
| bufferAmount | number |
4 | Used in virtual scrolling, the bufferAmount property controls the number of items preloaded in the background to ensure smoother and more seamless scrolling. |
| [items] | Array<any> |
[] |
Items array |
| [loading] | boolean |
- |
You can set the loading state from the outside (e.g. async items loading) |
| bindLabel | string |
label |
Object property to use for label. Default label |
| bindValue | string |
- |
Object property to use for selected model. By default binds to whole object. |
| placeholder | string |
- |
Placeholder text. |
Outputs used by the examples on this page:
| Output | Description |
|---|---|
| (scroll) | Fired when scrolled (only when [virtualScroll]="true"). Provides the start and end index of the currently available items. Can be used for loading more items in chunks before the user has scrolled all the way to the bottom of the list. |
| (scrollToEnd) | Fired when scrolled to the end of items. Can be used for loading more items in chunks. |
See the NgSelectComponent API reference for the complete list of inputs and outputs.