Cdk virtual-scroll inside mat-select for mat-option
I think i have solved this:
https://stackblitz.com/edit/angular-gs4scp
The key things are when the mat select opens panel we trigger cdkVirtualScrollViewPort scroll and check view port size.
openChange($event: boolean) {
console.log("open change", $event);
if ($event) {
this.cdkVirtualScrollViewPort.scrollToIndex(0);
this.cdkVirtualScrollViewPort.checkViewportSize();
} else {
}
}
Where we get the reference to the virtual scroll viewport using @ViewChild
@ViewChild(CdkVirtualScrollViewport, { static: false })
cdkVirtualScrollViewPort: CdkVirtualScrollViewport;
Other relevant pieces in the template are are pretty simple:-
<mat-form-field>
<mat-select [formControl]="itemSelect"
placeholder="Select Item"
(openedChange)="openChange($event)">
<mat-select-trigger>
{{ itemTrigger }}
</mat-select-trigger>
<cdk-virtual-scroll-viewport itemSize="5" minBufferPx="200" maxBufferPx="400" class="example-viewport-select">
<mat-option *cdkVirtualFor="let item of items" [value]="item"
(onSelectionChange)="onSelectionChange($event)">{{item}}</mat-option>
</cdk-virtual-scroll-viewport>
</mat-select>
<mat-hint>Justa hint</mat-hint>
</mat-form-field>
The virtual scroll viewport needs a size in order to know, how big the scroll container must be. This can be done by specifying the [itemSize]
property of <cdk-virtual-scroll-viewport>
and its height.
In your example the height of one <option>
item is 48px. If you want to show five items at once, the container size would be 5 * 48 = 240:
<mat-form-field>
<mat-select placeholder="State">
<cdk-virtual-scroll-viewport [itemSize]="48" [style.height.px]=5*48>
<mat-option *cdkVirtualFor="let state of states" [value]="state">
{{state}}
</mat-option>
</cdk-virtual-scroll-viewport>
</mat-select>
</mat-form-field>