Skip to content

Commit 57adfe4

Browse files
authored
fix(material/select): incorrect position if initialized late (#27198)
Fixes that in some cases the select was resolving its overlay origin too early which caused it to position itself incorrectly when it is opened. Fixes #27063.
1 parent 3703cc9 commit 57adfe4

File tree

2 files changed

+15
-17
lines changed

2 files changed

+15
-17
lines changed

src/material/select/select.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ import {
4040
import {ViewportRuler} from '@angular/cdk/scrolling';
4141
import {
4242
AfterContentInit,
43-
AfterViewInit,
4443
Attribute,
4544
ChangeDetectionStrategy,
4645
ChangeDetectorRef,
@@ -1283,7 +1282,7 @@ export class MatSelectTrigger {}
12831282
{provide: MAT_OPTION_PARENT_COMPONENT, useExisting: MatSelect},
12841283
],
12851284
})
1286-
export class MatSelect extends _MatSelectBase<MatSelectChange> implements OnInit, AfterViewInit {
1285+
export class MatSelect extends _MatSelectBase<MatSelectChange> implements OnInit {
12871286
@ContentChildren(MatOption, {descendants: true}) options: QueryList<MatOption>;
12881287
@ContentChildren(MAT_OPTGROUP, {descendants: true}) optionGroups: QueryList<MatOptgroup>;
12891288
@ContentChild(MAT_SELECT_TRIGGER) customTrigger: MatSelectTrigger;
@@ -1332,23 +1331,23 @@ export class MatSelect extends _MatSelectBase<MatSelectChange> implements OnInit
13321331
.pipe(takeUntil(this._destroy))
13331332
.subscribe(() => {
13341333
if (this.panelOpen) {
1335-
this._overlayWidth = this._getOverlayWidth();
1334+
this._overlayWidth = this._getOverlayWidth(this._preferredOverlayOrigin);
13361335
this._changeDetectorRef.detectChanges();
13371336
}
13381337
});
13391338
}
13401339

1341-
ngAfterViewInit() {
1342-
// Note that it's important that we read this in `ngAfterViewInit`, because
1343-
// reading it earlier will cause the form field to return a different element.
1340+
override open() {
1341+
// It's important that we read this as late as possible, because doing so earlier will
1342+
// return a different element since it's based on queries in the form field which may
1343+
// not have run yet. Also this needs to be assigned before we measure the overlay width.
13441344
if (this._parentFormField) {
13451345
this._preferredOverlayOrigin = this._parentFormField.getConnectedOverlayOrigin();
13461346
}
1347-
}
13481347

1349-
override open() {
1350-
this._overlayWidth = this._getOverlayWidth();
1348+
this._overlayWidth = this._getOverlayWidth(this._preferredOverlayOrigin);
13511349
super.open();
1350+
13521351
// Required for the MDC form field to pick up when the overlay has been opened.
13531352
this.stateChanges.next();
13541353
}
@@ -1393,12 +1392,14 @@ export class MatSelect extends _MatSelectBase<MatSelectChange> implements OnInit
13931392
}
13941393

13951394
/** Gets how wide the overlay panel should be. */
1396-
private _getOverlayWidth(): string | number {
1395+
private _getOverlayWidth(
1396+
preferredOrigin: ElementRef<ElementRef> | CdkOverlayOrigin | undefined,
1397+
): string | number {
13971398
if (this.panelWidth === 'auto') {
13981399
const refToMeasure =
1399-
this._preferredOverlayOrigin instanceof CdkOverlayOrigin
1400-
? this._preferredOverlayOrigin.elementRef
1401-
: this._preferredOverlayOrigin || this._elementRef;
1400+
preferredOrigin instanceof CdkOverlayOrigin
1401+
? preferredOrigin.elementRef
1402+
: preferredOrigin || this._elementRef;
14021403
return refToMeasure.nativeElement.getBoundingClientRect().width;
14031404
}
14041405

tools/public_api_guard/material/select.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import { _AbstractConstructor } from '@angular/material/core';
88
import { ActiveDescendantKeyManager } from '@angular/cdk/a11y';
99
import { AfterContentInit } from '@angular/core';
10-
import { AfterViewInit } from '@angular/core';
1110
import { AnimationTriggerMetadata } from '@angular/animations';
1211
import { BooleanInput } from '@angular/cdk/coercion';
1312
import { CanDisable } from '@angular/material/core';
@@ -76,7 +75,7 @@ export function MAT_SELECT_SCROLL_STRATEGY_PROVIDER_FACTORY(overlay: Overlay): (
7675
export const MAT_SELECT_TRIGGER: InjectionToken<MatSelectTrigger>;
7776

7877
// @public (undocumented)
79-
export class MatSelect extends _MatSelectBase<MatSelectChange> implements OnInit, AfterViewInit {
78+
export class MatSelect extends _MatSelectBase<MatSelectChange> implements OnInit {
8079
// (undocumented)
8180
close(): void;
8281
// (undocumented)
@@ -86,8 +85,6 @@ export class MatSelect extends _MatSelectBase<MatSelectChange> implements OnInit
8685
get hideSingleSelectionIndicator(): boolean;
8786
set hideSingleSelectionIndicator(value: BooleanInput);
8887
// (undocumented)
89-
ngAfterViewInit(): void;
90-
// (undocumented)
9188
ngOnInit(): void;
9289
// (undocumented)
9390
open(): void;

0 commit comments

Comments
 (0)