If you’re working with Angular Material and you have to integrate a Multi Select dropdown with a pretty large dataset with almost 5000 or more records and you have to provide Select All option in there then you would definitely need to use the Virtual Scrollbar otherwise you would go through a huge performance issue while selecting all.
Select All option with large dataset in Angular Material causes a huge performance issue and sometimes Maximum call Stack Size exceeded error
. I am here with a solution to this problem. Just follow the steps:-
Step 1:
Integrate Virtual Scrollbar into Material Mat Select. Use the below code for your reference:-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <mat-form-field> <mat-select [formControl]="multiSelectControl" multiple [value]="selected" (openedChange)="openChange($event)" placeholder="{{selected.length > 0 ? selectedTexts : 'Select'}}"> <mat-select-trigger> {{selectedTexts}} </mat-select-trigger> <cdk-virtual-scroll-viewport itemSize="50" [style.height.px]=5*48> <button (click)="selectAll()">Select All</button> <button (click)="clear()">Clear</button> <mat-option *cdkVirtualFor="let topping of toppingList" [value]="topping" (onSelectionChange)="onSelectionChange($event)">{{topping.viewValue}}</mat-option> </cdk-virtual-scroll-viewport> </mat-select> </mat-form-field> |
Step 2:
Make required Typescript codes to run the page. Use below code for your reference:-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | import { Component, ViewChild, ViewChildren, QueryList, ChangeDetectorRef } from "@angular/core"; import { FormControl } from "@angular/forms"; import { CdkVirtualScrollViewport, ScrollDispatcher } from "@angular/cdk/scrolling"; import { MatOption } from "@angular/material/core"; import { debounceTime, filter } from "rxjs/operators"; @Component({ selector: "my-app", templateUrl: "./app.component.html", styleUrls: ["./app.component.css"] }) export class AppComponent { title = "test-proj"; toppings = new FormControl(); toppingList: any[] = []; selected: any = []; @ViewChild(CdkVirtualScrollViewport, { static: true }) cdkVirtualScrollViewPort: CdkVirtualScrollViewport; multiSelectControl = new FormControl(); @ViewChildren(MatOption) options: QueryList<MatOption>; selectedTexts: string[] = []; constructor(private cd: ChangeDetectorRef, readonly sd: ScrollDispatcher) { for (let i = 0; i < 10000; i++) { this.toppingList.push({ id: i, viewValue: "option-" + i }); } } ngAfterViewInit(): void { this.sd .scrolled() .pipe(filter(scrollable => this.cdkVirtualScrollViewPort === scrollable)) .subscribe(() => { let needUpdate = false; this.options.forEach(option => { const selected = this.selected.includes(option.value); if (selected && !option.selected) { option.select(); needUpdate = true; } else if (!selected && option.selected) { option.deselect(); needUpdate = true; } }); if (needUpdate) { this.cd.detectChanges(); } }); } displaySelectedTexts() { this.selectedTexts = this.selected.map(x => x.viewValue); } foropen() { this.cdkVirtualScrollViewPort.scrollToIndex(5); } selectAll() { this.selected = Array.from(this.toppingList); this.multiSelectControl.patchValue(this.toppingList); this.displaySelectedTexts(); } clear() { this.selected = []; this.multiSelectControl.patchValue([]); } openChange($event: boolean) { if ($event) { this.foropen(); this.cdkVirtualScrollViewPort.scrollToIndex(0); this.cdkVirtualScrollViewPort.checkViewportSize(); this.displaySelectedTexts(); } } onSelectionChange(change): void { if (!change.isUserInput) { return; } console.log(change.source.value); const value = change.source.value; const idx = this.selected.indexOf(change.source.value); if (idx > -1) { this.selected.splice(idx, 1); } else { this.selected.push(value); } this.displaySelectedTexts(); } } |
That’s it!!!
I have here a working example ready at Stackblitz. You can just open this link and use codes.
Write me up for any change or if its not working as per your expectation!
Thank you!
Excelent Work, thanks