Skip to content

Commit d773cce

Browse files
crisbetommalerba
authored andcommitted
fix(select): not picking up indirect descendant option groups (#17458)
Fixes `mat-select` not picking up option groups that aren't direct descedants.
1 parent 4663d8f commit d773cce

File tree

2 files changed

+65
-2
lines changed

2 files changed

+65
-2
lines changed

src/material/select/select.spec.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3113,6 +3113,7 @@ describe('MatSelect', () => {
31133113
BasicSelect,
31143114
MultiSelect,
31153115
SelectWithGroups,
3116+
SelectWithIndirectDescendantGroups,
31163117
])));
31173118

31183119
beforeEach((inject([ViewportRuler], (vr: ViewportRuler) => {
@@ -3293,6 +3294,45 @@ describe('MatSelect', () => {
32933294
checkTriggerAlignedWithOption(7, groupFixture.componentInstance.select);
32943295
}));
32953296

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+
32963336
});
32973337

32983338
describe('limited space to open vertically', () => {
@@ -4814,6 +4854,29 @@ class SelectWithGroups {
48144854
@ViewChildren(MatOption) options: QueryList<MatOption>;
48154855
}
48164856

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+
48174880
@Component({
48184881
selector: 'select-with-groups',
48194882
template: `

src/material/select/select.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,10 +336,10 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
336336
@ViewChild(CdkConnectedOverlay, {static: false}) overlayDir: CdkConnectedOverlay;
337337

338338
/** All of the defined select options. */
339-
@ContentChildren(MatOption, { descendants: true }) options: QueryList<MatOption>;
339+
@ContentChildren(MatOption, {descendants: true}) options: QueryList<MatOption>;
340340

341341
/** All of the defined groups of options. */
342-
@ContentChildren(MatOptgroup) optionGroups: QueryList<MatOptgroup>;
342+
@ContentChildren(MatOptgroup, {descendants: true}) optionGroups: QueryList<MatOptgroup>;
343343

344344
/** Classes to be passed to the select panel. Supports the same syntax as `ngClass`. */
345345
@Input() panelClass: string|string[]|Set<string>|{[key: string]: any};

0 commit comments

Comments
 (0)