Skip to content

fix(select): not picking up indirect descendant option groups #17458

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions src/material/select/select.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3113,6 +3113,7 @@ describe('MatSelect', () => {
BasicSelect,
MultiSelect,
SelectWithGroups,
SelectWithIndirectDescendantGroups,
])));

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

it('should account for indirect preceding label groups when aligning the option',
fakeAsync(() => {
// Test is off-by-one on edge for some reason, but verified that it looks correct through
// manual testing.
if (platform.EDGE) {
return;
}

fixture.destroy();

let groupFixture = TestBed.createComponent(SelectWithIndirectDescendantGroups);
groupFixture.detectChanges();
trigger = groupFixture.debugElement.query(By.css('.mat-select-trigger'))!.nativeElement;
formField = groupFixture.debugElement.query(By.css('mat-form-field'))!.nativeElement;

formField.style.position = 'fixed';
formField.style.top = '200px';
formField.style.left = '100px';

// Select an option in the third group, which has a couple of group labels before it.
groupFixture.componentInstance.control.setValue('vulpix-7');
groupFixture.detectChanges();

trigger.click();
groupFixture.detectChanges();
flush();

const scrollContainer = document.querySelector('.cdk-overlay-pane .mat-select-panel')!;

// The selected option should be scrolled to the center of the panel.
// This will be its original offset from the scrollTop - half the panel height + half the
// option height. 10 (option index + 3 group labels before it) * 48 (option height) = 480
// 480 (offset from scrollTop) - 256/2 + 48/2 = 376px
expect(Math.floor(scrollContainer.scrollTop))
.toBe(376, `Expected overlay panel to be scrolled to center the selected option.`);

checkTriggerAlignedWithOption(7, groupFixture.componentInstance.select);
}));

});

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

@Component({
selector: 'select-with-indirect-groups',
// Note that we need the blank `ngSwitch` in order to have
// a directive between `mat-select` and `mat-optgroup`.
template: `
<mat-form-field>
<mat-select placeholder="Pokemon" [formControl]="control">
<ng-container [ngSwitch]="true">
<mat-optgroup *ngFor="let group of pokemonTypes" [label]="group.name"
[disabled]="group.disabled">
<mat-option *ngFor="let pokemon of group.pokemon" [value]="pokemon.value">
{{ pokemon.viewValue }}
</mat-option>
</mat-optgroup>
<mat-option value="mime-11">Mr. Mime</mat-option>
</ng-container>
</mat-select>
</mat-form-field>
`
})
class SelectWithIndirectDescendantGroups extends SelectWithGroups {
}

@Component({
selector: 'select-with-groups',
template: `
Expand Down
4 changes: 2 additions & 2 deletions src/material/select/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,10 +336,10 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
@ViewChild(CdkConnectedOverlay, {static: false}) overlayDir: CdkConnectedOverlay;

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

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

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