Skip to content

Commit

Permalink
fix(material/select): incorrect position if initialized late (#27198)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
crisbeto committed May 31, 2023
1 parent 3703cc9 commit 57adfe4
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 17 deletions.
27 changes: 14 additions & 13 deletions src/material/select/select.ts
Expand Up @@ -40,7 +40,6 @@ import {
import {ViewportRuler} from '@angular/cdk/scrolling';
import {
AfterContentInit,
AfterViewInit,
Attribute,
ChangeDetectionStrategy,
ChangeDetectorRef,
Expand Down Expand Up @@ -1283,7 +1282,7 @@ export class MatSelectTrigger {}
{provide: MAT_OPTION_PARENT_COMPONENT, useExisting: MatSelect},
],
})
export class MatSelect extends _MatSelectBase<MatSelectChange> implements OnInit, AfterViewInit {
export class MatSelect extends _MatSelectBase<MatSelectChange> implements OnInit {
@ContentChildren(MatOption, {descendants: true}) options: QueryList<MatOption>;
@ContentChildren(MAT_OPTGROUP, {descendants: true}) optionGroups: QueryList<MatOptgroup>;
@ContentChild(MAT_SELECT_TRIGGER) customTrigger: MatSelectTrigger;
Expand Down Expand Up @@ -1332,23 +1331,23 @@ export class MatSelect extends _MatSelectBase<MatSelectChange> implements OnInit
.pipe(takeUntil(this._destroy))
.subscribe(() => {
if (this.panelOpen) {
this._overlayWidth = this._getOverlayWidth();
this._overlayWidth = this._getOverlayWidth(this._preferredOverlayOrigin);
this._changeDetectorRef.detectChanges();
}
});
}

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

override open() {
this._overlayWidth = this._getOverlayWidth();
this._overlayWidth = this._getOverlayWidth(this._preferredOverlayOrigin);
super.open();

// Required for the MDC form field to pick up when the overlay has been opened.
this.stateChanges.next();
}
Expand Down Expand Up @@ -1393,12 +1392,14 @@ export class MatSelect extends _MatSelectBase<MatSelectChange> implements OnInit
}

/** Gets how wide the overlay panel should be. */
private _getOverlayWidth(): string | number {
private _getOverlayWidth(
preferredOrigin: ElementRef<ElementRef> | CdkOverlayOrigin | undefined,
): string | number {
if (this.panelWidth === 'auto') {
const refToMeasure =
this._preferredOverlayOrigin instanceof CdkOverlayOrigin
? this._preferredOverlayOrigin.elementRef
: this._preferredOverlayOrigin || this._elementRef;
preferredOrigin instanceof CdkOverlayOrigin
? preferredOrigin.elementRef
: preferredOrigin || this._elementRef;
return refToMeasure.nativeElement.getBoundingClientRect().width;
}

Expand Down
5 changes: 1 addition & 4 deletions tools/public_api_guard/material/select.md
Expand Up @@ -7,7 +7,6 @@
import { _AbstractConstructor } from '@angular/material/core';
import { ActiveDescendantKeyManager } from '@angular/cdk/a11y';
import { AfterContentInit } from '@angular/core';
import { AfterViewInit } from '@angular/core';
import { AnimationTriggerMetadata } from '@angular/animations';
import { BooleanInput } from '@angular/cdk/coercion';
import { CanDisable } from '@angular/material/core';
Expand Down Expand Up @@ -76,7 +75,7 @@ export function MAT_SELECT_SCROLL_STRATEGY_PROVIDER_FACTORY(overlay: Overlay): (
export const MAT_SELECT_TRIGGER: InjectionToken<MatSelectTrigger>;

// @public (undocumented)
export class MatSelect extends _MatSelectBase<MatSelectChange> implements OnInit, AfterViewInit {
export class MatSelect extends _MatSelectBase<MatSelectChange> implements OnInit {
// (undocumented)
close(): void;
// (undocumented)
Expand All @@ -86,8 +85,6 @@ export class MatSelect extends _MatSelectBase<MatSelectChange> implements OnInit
get hideSingleSelectionIndicator(): boolean;
set hideSingleSelectionIndicator(value: BooleanInput);
// (undocumented)
ngAfterViewInit(): void;
// (undocumented)
ngOnInit(): void;
// (undocumented)
open(): void;
Expand Down

0 comments on commit 57adfe4

Please sign in to comment.