diff --git a/e2e/components/menu/menu.e2e.ts b/e2e/components/menu/menu.e2e.ts
index dcb5202925e2..bdda6616b2ac 100644
--- a/e2e/components/menu/menu.e2e.ts
+++ b/e2e/components/menu/menu.e2e.ts
@@ -15,12 +15,6 @@ describe('menu', () => {
expect(page.menu().getText()).toEqual("One\nTwo\nThree\nFour");
});
- it('should close menu when area outside menu is clicked', () => {
- page.trigger().click();
- page.body().click();
- page.expectMenuPresent(false);
- });
-
it('should close menu when menu item is clicked', () => {
page.trigger().click();
page.items(0).click();
diff --git a/src/lib/menu/menu-directive.ts b/src/lib/menu/menu-directive.ts
index 51c038f83383..2a3eeaa36b7c 100644
--- a/src/lib/menu/menu-directive.ts
+++ b/src/lib/menu/menu-directive.ts
@@ -27,7 +27,6 @@ import {UP_ARROW, DOWN_ARROW, TAB} from '../core';
exportAs: 'mdMenu'
})
export class MdMenu {
- _showClickCatcher: boolean = false;
private _focusedItemIndex: number = 0;
// config object to be passed into the menu's ngClass
@@ -61,15 +60,6 @@ export class MdMenu {
@Output() close = new EventEmitter;
- /**
- * This function toggles the display of the menu's click catcher element.
- * This element covers the viewport when the menu is open to detect clicks outside the menu.
- * TODO: internal
- */
- _setClickCatcher(bool: boolean): void {
- this._showClickCatcher = bool;
- }
-
/**
* Focus the first item in the menu. This method is used by the menu trigger
* to focus the first item when the menu is opened by the ENTER key.
diff --git a/src/lib/menu/menu-trigger.ts b/src/lib/menu/menu-trigger.ts
index a77346ad2560..fc2c47f2045e 100644
--- a/src/lib/menu/menu-trigger.ts
+++ b/src/lib/menu/menu-trigger.ts
@@ -23,6 +23,7 @@ import {
HorizontalConnectionPos,
VerticalConnectionPos
} from '../core';
+import { Subscription } from 'rxjs/Subscription';
/**
* This directive is intended to be used in conjunction with an md-menu tag. It is
@@ -40,6 +41,7 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy {
private _portal: TemplatePortal;
private _overlayRef: OverlayRef;
private _menuOpen: boolean = false;
+ private _backdropSubscription: Subscription;
// tracking input type is necessary so it's possible to only auto-focus
// the first item of the list when the menu is opened via the keyboard
@@ -70,6 +72,7 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy {
if (!this._menuOpen) {
this._createOverlay();
this._overlayRef.attach(this._portal);
+ this._subscribeToBackdrop();
this._initMenu();
}
}
@@ -77,6 +80,7 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy {
closeMenu(): void {
if (this._overlayRef) {
this._overlayRef.detach();
+ this._backdropSubscription.unsubscribe();
this._resetMenu();
}
}
@@ -85,6 +89,10 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy {
if (this._overlayRef) {
this._overlayRef.dispose();
this._overlayRef = null;
+
+ if (this._backdropSubscription) {
+ this._backdropSubscription.unsubscribe();
+ }
}
}
@@ -92,6 +100,17 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy {
this._renderer.invokeElementMethod(this._element.nativeElement, 'focus');
}
+ /**
+ * This method ensures that the menu closes when the overlay backdrop is clicked.
+ */
+ private _subscribeToBackdrop(): void {
+ // Unsubscribes when the menu closes instead of using first() because the latter
+ // would not catch clicks from within the menu and properly unsubscribe itself.
+ this._backdropSubscription = this._overlayRef.backdropClick().subscribe(() => {
+ this.closeMenu();
+ });
+ }
+
/**
* This method sets the menu state to open and focuses the first item if
* the menu was opened via the keyboard.
@@ -120,7 +139,6 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy {
// set state rather than toggle to support triggers sharing a menu
private _setIsMenuOpen(isOpen: boolean): void {
this._menuOpen = isOpen;
- this.menu._setClickCatcher(isOpen);
this._menuOpen ? this.onMenuOpen.emit(null) : this.onMenuClose.emit(null);
}
@@ -152,6 +170,8 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy {
private _getOverlayConfig(): OverlayState {
const overlayState = new OverlayState();
overlayState.positionStrategy = this._getPosition();
+ overlayState.hasBackdrop = true;
+ overlayState.backdropClass = 'md-overlay-transparent-backdrop';
return overlayState;
}
diff --git a/src/lib/menu/menu.html b/src/lib/menu/menu.html
index bb6d522a79d7..58721749878e 100644
--- a/src/lib/menu/menu.html
+++ b/src/lib/menu/menu.html
@@ -4,4 +4,4 @@