diff --git a/src/lib/menu/menu-directive.ts b/src/lib/menu/menu-directive.ts index 3a473e117346..a58d36e9f15f 100644 --- a/src/lib/menu/menu-directive.ts +++ b/src/lib/menu/menu-directive.ts @@ -187,7 +187,6 @@ export class MatMenu implements AfterContentInit, MatMenuPanel, OnDestroy { ngOnDestroy() { this._tabSubscription.unsubscribe(); - this.closed.emit(); this.closed.complete(); } diff --git a/src/lib/menu/menu-trigger.ts b/src/lib/menu/menu-trigger.ts index 303bf557329d..3a82acb7af4d 100644 --- a/src/lib/menu/menu-trigger.ts +++ b/src/lib/menu/menu-trigger.ts @@ -193,9 +193,7 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy { openMenu(): void { if (!this._menuOpen) { this._createOverlay().attach(this._portal); - this._closeSubscription = this._menuClosingActions().subscribe(() => { - this.menu.close.emit(); - }); + this._closeSubscription = this._menuClosingActions().subscribe(() => this.closeMenu()); this._initMenu(); if (this.menu instanceof MatMenu) { @@ -218,8 +216,8 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy { private _destroyMenu() { if (this._overlayRef && this.menuOpen) { this._resetMenu(); - this._overlayRef.detach(); this._closeSubscription.unsubscribe(); + this._overlayRef.detach(); if (this.menu instanceof MatMenu) { this.menu._resetAnimation(); @@ -400,13 +398,14 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy { /** Returns a stream that emits whenever an action that should close the menu occurs. */ private _menuClosingActions() { const backdrop = this._overlayRef!.backdropClick(); + const detachments = this._overlayRef!.detachments(); const parentClose = this._parentMenu ? this._parentMenu.close : observableOf(); const hover = this._parentMenu ? this._parentMenu._hovered().pipe( filter(active => active !== this._menuItemInstance), filter(() => this._menuOpen) ) : observableOf(); - return merge(backdrop, parentClose, hover); + return merge(backdrop, parentClose, hover, detachments); } /** Handles mouse presses on the trigger. */ diff --git a/src/lib/menu/menu.spec.ts b/src/lib/menu/menu.spec.ts index e9918a1edd57..c6d20c992dee 100644 --- a/src/lib/menu/menu.spec.ts +++ b/src/lib/menu/menu.spec.ts @@ -13,7 +13,7 @@ import { QueryList, } from '@angular/core'; import {Direction, Directionality} from '@angular/cdk/bidi'; -import {OverlayContainer} from '@angular/cdk/overlay'; +import {OverlayContainer, Overlay} from '@angular/cdk/overlay'; import {ESCAPE, LEFT_ARROW, RIGHT_ARROW} from '@angular/cdk/keycodes'; import { MAT_MENU_DEFAULT_OPTIONS, @@ -25,7 +25,7 @@ import { MenuPositionY, MatMenuItem, } from './index'; -import {MENU_PANEL_TOP_PADDING} from './menu-trigger'; +import {MENU_PANEL_TOP_PADDING, MAT_MENU_SCROLL_STRATEGY} from './menu-trigger'; import {MatRipple} from '@angular/material/core'; import { dispatchKeyboardEvent, @@ -35,6 +35,8 @@ import { createMouseEvent, dispatchFakeEvent, } from '@angular/cdk/testing'; +import {Subject} from 'rxjs/Subject'; +import {ScrollDispatcher} from '@angular/cdk/scrolling'; describe('MatMenu', () => { @@ -242,6 +244,34 @@ describe('MatMenu', () => { expect(document.activeElement).toBe(panel, 'Expected the panel to be focused.'); }); + it('should close the menu when using the CloseScrollStrategy', fakeAsync(() => { + const scrolledSubject = new Subject(); + + TestBed.overrideProvider(ScrollDispatcher, { + deps: [], + useFactory: () => ({scrolled: () => scrolledSubject}) + }); + + TestBed.overrideProvider(MAT_MENU_SCROLL_STRATEGY, { + deps: [Overlay], + useFactory: (overlay: Overlay) => () => overlay.scrollStrategies.close() + }); + + const fixture = TestBed.createComponent(SimpleMenu); + const trigger = fixture.componentInstance.trigger; + + fixture.detectChanges(); + trigger.openMenu(); + fixture.detectChanges(); + + expect(trigger.menuOpen).toBe(true); + + scrolledSubject.next(); + tick(500); + + expect(trigger.menuOpen).toBe(false); + })); + describe('positions', () => { let fixture: ComponentFixture; let panel: HTMLElement;