13

Has anyone been able to use virtual-scroll inside mat-select as shown below ?

<mat-form-field>
    <mat-select placeholder="State">
        <cdk-virtual-scroll-viewport autosize>
            <mat-option *cdkVirtualFor="let state of states" [value]="state">{{state}}</mat-option>
        </cdk-virtual-scroll-viewport>
    </mat-select>
</mat-form-field>

As you can see https://stackblitz.com/edit/angular-h4xptu?file=app%2Fselect-reset-example.html it does not work - causes weird blank space as you scroll.

maiermic
  • 4,764
  • 6
  • 38
  • 77
bhantol
  • 9,368
  • 7
  • 44
  • 81

3 Answers3

10

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>
maiermic
  • 4,764
  • 6
  • 38
  • 77
bhantol
  • 9,368
  • 7
  • 44
  • 81
9

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>
maiermic
  • 4,764
  • 6
  • 38
  • 77
kevobt
  • 146
  • 1
  • 6
  • Blank space is still there https://stackblitz.com/edit/angular-h4xptu?file=app%2Fselect-reset-example.html . Try this scroll down, close the drop down, then open again. You can head over to https://github.com/angular/material2/issues/13087 opened and workarounds but there is a inherent problem hence the item is still open. – bhantol Dec 05 '18 at 15:12
  • Perhaps we can combine yours with https://github.com/angular/material2/issues/13087#issuecomment-442072410 – bhantol Dec 05 '18 at 15:13
  • I don't get it. My solution works perfectly fine. As @yusijs stated in this [issue](https://github.com/angular/material2/issues/13087#issuecomment-442072410), the itemSize property is the height in pixels of one item -- not the array length. I wouldn't use autosize, because it is not stable, yet. – kevobt Dec 05 '18 at 20:20
  • 1
    Try this (your solution) https://stackblitz.com/edit/angular-h4xptu-dy6nml?file=app/select-reset-example.html steps: 1) Open drop down 2) scroll all the way down 3) close drop down 4) Open drop down...I am seeing a big blank drop down. What are you seeing ? – bhantol Dec 05 '18 at 20:42
  • Yep, I see it. Must be a bug -- this is certainly not intended. – kevobt Dec 05 '18 at 20:54
-1

Add an additional mat-option using *ngFor as if you were not using cdk virtual scroll. This does not add any additional options to your select list, but does allow a default selected value, while also allowing cdk-virtual scroll to do its thing.

<mat-select placeholder="State">
  <cdk-virtual-scroll-viewport itemSize="10" [style.height.px]=10*100>
        <mat-option *cdkVirtualFor="let state of states" [value]="state">{{state}}</mat-option>
  </cdk-virtual-scroll-viewport>
  <mat-option *ngFor="let state of states" [value]="state"> 
  {{state}}</mat-option>
 </mat-select>
NoDiced
  • 33
  • 1
  • 8
  • 1
    This makes no sense. It will add the whole list to the dom again. You can't see them visually, but they are there. Which will again choke the browser if the list if huge. This defeats the purpose of using the virtual scroll in the first place – ZolaKt Jun 01 '22 at 13:11
  • 1
    If you have a better working option, we would all appreciate it. The solution that was voted up did not work for me. – NoDiced Jun 12 '22 at 16:25