Dealing with large datasets in angular material multi select is tough especially when you do not have Virtual Scrollbar integrated. I will explain steps on how to use Virtual Scollbar in Angular Mat Multi Select.
Here is a quick info of what is Virtual Scrollbar:- It is a way to improve the performance of scrollable items like Dropdown, Table etc. Suppose you have to display more than 10k records in a dropdown or a table, then without using Virtual Scrollbar, it becomes performance issue to deal with. More info.
We will be integrating Virtual Scroll in a Mat Multi Select control.
Step 1:
Use a Mat Multi Select control. Check below code for reference:
<mat-form-field>
<mat-select [formControl]="multiSelectControl" multiple [value]="selected" (openedChange)="openChange($event)"
placeholder="Select">
<cdk-virtual-scroll-viewport itemSize="50" [style.height.px]=5*48>
<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>
Here you will notice two things:
- cdk-virtual-scroll-viewport
- *cdkVirtualFor
Those are the key tag and directive to work with Virtual Scroll bar in Angular.
Step 2:
Make required changes in Typescript code. Check below code for reference:
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 { 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>;
constructor(private cd: ChangeDetectorRef, readonly sd: ScrollDispatcher) {
for (let i = 0; i < 100000; 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();
}
});
}
foropen() {
this.cdkVirtualScrollViewPort.scrollToIndex(5);
}
openChange($event: boolean) {
if ($event) {
this.foropen();
this.cdkVirtualScrollViewPort.scrollToIndex(0);
this.cdkVirtualScrollViewPort.checkViewportSize();
}
}
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);
}
}
}
Just for reference, here is a working code example running on Stackblitz.
Write me up if there is any error while integrating it.
That’s it!!
Nice!
Give an explanation to your code. Not able to understand
Sadly, they can’t give you an explanation of this code because they didn’t write it. They stole this from a StackOverflow post from 2020 and added a useless introduction to it.
You are commenting on a comment that is 1 year old. By the way this post was for my personal use to remind me this code if ever I stuck implementing a virtual scroll bar. You can check my other articles on Angular. If you don’t find any value, you can leave the blog.