mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(menu): panel positions not changing if position is updated after first open (#11707)
Fixes the menu's panel position not being accurate if it's `xPosition` or `yPosition` is updated after it has been opened for the first time. Fixes #11668.
This commit is contained in:
committed by
tinayuangao
parent
f59cf5954c
commit
50ea837250
@@ -196,6 +196,7 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy {
|
||||
}
|
||||
|
||||
const overlayRef = this._createOverlay();
|
||||
this._setPosition(overlayRef.getConfig().positionStrategy as FlexibleConnectedPositionStrategy);
|
||||
overlayRef.attach(this._portal);
|
||||
|
||||
if (this.menu.lazyContent) {
|
||||
@@ -350,7 +351,9 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy {
|
||||
*/
|
||||
private _getOverlayConfig(): OverlayConfig {
|
||||
return new OverlayConfig({
|
||||
positionStrategy: this._getPosition(),
|
||||
positionStrategy: this._overlay.position()
|
||||
.flexibleConnectedTo(this._element)
|
||||
.withTransformOriginOn('.mat-menu-panel'),
|
||||
hasBackdrop: this.menu.hasBackdrop == null ? !this.triggersSubmenu() : this.menu.hasBackdrop,
|
||||
backdropClass: this.menu.backdropClass || 'cdk-overlay-transparent-backdrop',
|
||||
scrollStrategy: this._scrollStrategy(),
|
||||
@@ -375,11 +378,11 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method builds the position strategy for the overlay, so the menu is properly connected
|
||||
* to the trigger.
|
||||
* @returns ConnectedPositionStrategy
|
||||
* Sets the appropriate positions on a position strategy
|
||||
* so the overlay connects with the trigger correctly.
|
||||
* @param positionStrategy Strategy whose position to update.
|
||||
*/
|
||||
private _getPosition(): FlexibleConnectedPositionStrategy {
|
||||
private _setPosition(positionStrategy: FlexibleConnectedPositionStrategy) {
|
||||
let [originX, originFallbackX]: HorizontalConnectionPos[] =
|
||||
this.menu.xPosition === 'before' ? ['end', 'start'] : ['start', 'end'];
|
||||
|
||||
@@ -401,27 +404,24 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy {
|
||||
originFallbackY = overlayFallbackY === 'top' ? 'bottom' : 'top';
|
||||
}
|
||||
|
||||
return this._overlay.position()
|
||||
.flexibleConnectedTo(this._element)
|
||||
.withTransformOriginOn('.mat-menu-panel')
|
||||
.withPositions([
|
||||
{originX, originY, overlayX, overlayY, offsetY},
|
||||
{originX: originFallbackX, originY, overlayX: overlayFallbackX, overlayY, offsetY},
|
||||
{
|
||||
originX,
|
||||
originY: originFallbackY,
|
||||
overlayX,
|
||||
overlayY: overlayFallbackY,
|
||||
offsetY: -offsetY
|
||||
},
|
||||
{
|
||||
originX: originFallbackX,
|
||||
originY: originFallbackY,
|
||||
overlayX: overlayFallbackX,
|
||||
overlayY: overlayFallbackY,
|
||||
offsetY: -offsetY
|
||||
}
|
||||
]);
|
||||
positionStrategy.withPositions([
|
||||
{originX, originY, overlayX, overlayY, offsetY},
|
||||
{originX: originFallbackX, originY, overlayX: overlayFallbackX, overlayY, offsetY},
|
||||
{
|
||||
originX,
|
||||
originY: originFallbackY,
|
||||
overlayX,
|
||||
overlayY: overlayFallbackY,
|
||||
offsetY: -offsetY
|
||||
},
|
||||
{
|
||||
originX: originFallbackX,
|
||||
originY: originFallbackY,
|
||||
overlayX: overlayFallbackX,
|
||||
overlayY: overlayFallbackY,
|
||||
offsetY: -offsetY
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
/** Cleans up the active subscriptions. */
|
||||
|
||||
@@ -512,13 +512,13 @@ describe('MatMenu', () => {
|
||||
|
||||
describe('positions', () => {
|
||||
let fixture: ComponentFixture<PositionedMenu>;
|
||||
let panel: HTMLElement;
|
||||
let trigger: HTMLElement;
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = createComponent(PositionedMenu);
|
||||
fixture.detectChanges();
|
||||
|
||||
const trigger = fixture.componentInstance.triggerEl.nativeElement;
|
||||
trigger = fixture.componentInstance.triggerEl.nativeElement;
|
||||
|
||||
// Push trigger to the bottom edge of viewport,so it has space to open "above"
|
||||
trigger.style.position = 'fixed';
|
||||
@@ -526,13 +526,14 @@ describe('MatMenu', () => {
|
||||
|
||||
// Push trigger to the right, so it has space to open "before"
|
||||
trigger.style.left = '100px';
|
||||
|
||||
fixture.componentInstance.trigger.openMenu();
|
||||
fixture.detectChanges();
|
||||
panel = overlayContainerElement.querySelector('.mat-menu-panel') as HTMLElement;
|
||||
});
|
||||
|
||||
it('should append mat-menu-before if the x position is changed', () => {
|
||||
fixture.componentInstance.trigger.openMenu();
|
||||
fixture.detectChanges();
|
||||
|
||||
const panel = overlayContainerElement.querySelector('.mat-menu-panel') as HTMLElement;
|
||||
|
||||
expect(panel.classList).toContain('mat-menu-before');
|
||||
expect(panel.classList).not.toContain('mat-menu-after');
|
||||
|
||||
@@ -544,6 +545,11 @@ describe('MatMenu', () => {
|
||||
});
|
||||
|
||||
it('should append mat-menu-above if the y position is changed', () => {
|
||||
fixture.componentInstance.trigger.openMenu();
|
||||
fixture.detectChanges();
|
||||
|
||||
const panel = overlayContainerElement.querySelector('.mat-menu-panel') as HTMLElement;
|
||||
|
||||
expect(panel.classList).toContain('mat-menu-above');
|
||||
expect(panel.classList).not.toContain('mat-menu-below');
|
||||
|
||||
@@ -564,12 +570,41 @@ describe('MatMenu', () => {
|
||||
newFixture.detectChanges();
|
||||
newFixture.componentInstance.trigger.openMenu();
|
||||
newFixture.detectChanges();
|
||||
panel = overlayContainerElement.querySelector('.mat-menu-panel') as HTMLElement;
|
||||
const panel = overlayContainerElement.querySelector('.mat-menu-panel') as HTMLElement;
|
||||
|
||||
expect(panel.classList).toContain('mat-menu-below');
|
||||
expect(panel.classList).toContain('mat-menu-after');
|
||||
});
|
||||
|
||||
it('should be able to update the position after the first open', () => {
|
||||
trigger.style.position = 'fixed';
|
||||
trigger.style.top = '200px';
|
||||
|
||||
fixture.componentInstance.yPosition = 'above';
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.componentInstance.trigger.openMenu();
|
||||
fixture.detectChanges();
|
||||
|
||||
let panel = overlayContainerElement.querySelector('.mat-menu-panel') as HTMLElement;
|
||||
|
||||
expect(Math.floor(panel.getBoundingClientRect().bottom))
|
||||
.toBe(Math.floor(trigger.getBoundingClientRect().bottom), 'Expected menu to open above');
|
||||
|
||||
fixture.componentInstance.trigger.closeMenu();
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.componentInstance.yPosition = 'below';
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.componentInstance.trigger.openMenu();
|
||||
fixture.detectChanges();
|
||||
panel = overlayContainerElement.querySelector('.mat-menu-panel') as HTMLElement;
|
||||
|
||||
expect(Math.floor(panel.getBoundingClientRect().top))
|
||||
.toBe(Math.floor(trigger.getBoundingClientRect().top), 'Expected menu to open below');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('fallback positions', () => {
|
||||
|
||||
Reference in New Issue
Block a user