@@ -3113,6 +3113,7 @@ describe('MatSelect', () => {
3113
3113
BasicSelect ,
3114
3114
MultiSelect ,
3115
3115
SelectWithGroups ,
3116
+ SelectWithIndirectDescendantGroups ,
3116
3117
] ) ) ) ;
3117
3118
3118
3119
beforeEach ( ( inject ( [ ViewportRuler ] , ( vr : ViewportRuler ) => {
@@ -3293,6 +3294,45 @@ describe('MatSelect', () => {
3293
3294
checkTriggerAlignedWithOption ( 7 , groupFixture . componentInstance . select ) ;
3294
3295
} ) ) ;
3295
3296
3297
+ it ( 'should account for indirect preceding label groups when aligning the option' ,
3298
+ fakeAsync ( ( ) => {
3299
+ // Test is off-by-one on edge for some reason, but verified that it looks correct through
3300
+ // manual testing.
3301
+ if ( platform . EDGE ) {
3302
+ return ;
3303
+ }
3304
+
3305
+ fixture . destroy ( ) ;
3306
+
3307
+ let groupFixture = TestBed . createComponent ( SelectWithIndirectDescendantGroups ) ;
3308
+ groupFixture . detectChanges ( ) ;
3309
+ trigger = groupFixture . debugElement . query ( By . css ( '.mat-select-trigger' ) ) ! . nativeElement ;
3310
+ formField = groupFixture . debugElement . query ( By . css ( 'mat-form-field' ) ) ! . nativeElement ;
3311
+
3312
+ formField . style . position = 'fixed' ;
3313
+ formField . style . top = '200px' ;
3314
+ formField . style . left = '100px' ;
3315
+
3316
+ // Select an option in the third group, which has a couple of group labels before it.
3317
+ groupFixture . componentInstance . control . setValue ( 'vulpix-7' ) ;
3318
+ groupFixture . detectChanges ( ) ;
3319
+
3320
+ trigger . click ( ) ;
3321
+ groupFixture . detectChanges ( ) ;
3322
+ flush ( ) ;
3323
+
3324
+ const scrollContainer = document . querySelector ( '.cdk-overlay-pane .mat-select-panel' ) ! ;
3325
+
3326
+ // The selected option should be scrolled to the center of the panel.
3327
+ // This will be its original offset from the scrollTop - half the panel height + half the
3328
+ // option height. 10 (option index + 3 group labels before it) * 48 (option height) = 480
3329
+ // 480 (offset from scrollTop) - 256/2 + 48/2 = 376px
3330
+ expect ( Math . floor ( scrollContainer . scrollTop ) )
3331
+ . toBe ( 376 , `Expected overlay panel to be scrolled to center the selected option.` ) ;
3332
+
3333
+ checkTriggerAlignedWithOption ( 7 , groupFixture . componentInstance . select ) ;
3334
+ } ) ) ;
3335
+
3296
3336
} ) ;
3297
3337
3298
3338
describe ( 'limited space to open vertically' , ( ) => {
@@ -4814,6 +4854,29 @@ class SelectWithGroups {
4814
4854
@ViewChildren ( MatOption ) options : QueryList < MatOption > ;
4815
4855
}
4816
4856
4857
+ @Component ( {
4858
+ selector : 'select-with-indirect-groups' ,
4859
+ // Note that we need the blank `ngSwitch` in order to have
4860
+ // a directive between `mat-select` and `mat-optgroup`.
4861
+ template : `
4862
+ <mat-form-field>
4863
+ <mat-select placeholder="Pokemon" [formControl]="control">
4864
+ <ng-container [ngSwitch]="true">
4865
+ <mat-optgroup *ngFor="let group of pokemonTypes" [label]="group.name"
4866
+ [disabled]="group.disabled">
4867
+ <mat-option *ngFor="let pokemon of group.pokemon" [value]="pokemon.value">
4868
+ {{ pokemon.viewValue }}
4869
+ </mat-option>
4870
+ </mat-optgroup>
4871
+ <mat-option value="mime-11">Mr. Mime</mat-option>
4872
+ </ng-container>
4873
+ </mat-select>
4874
+ </mat-form-field>
4875
+ `
4876
+ } )
4877
+ class SelectWithIndirectDescendantGroups extends SelectWithGroups {
4878
+ }
4879
+
4817
4880
@Component ( {
4818
4881
selector : 'select-with-groups' ,
4819
4882
template : `
0 commit comments