From 3c724446010ac07660e0070d8e18832df53e9fa5 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Sun, 31 Jul 2016 10:05:05 +0300 Subject: [PATCH] feat(menu): expose close method on element scope Exposes the $mdCloseMenu method on the menu's scope, allowing for custom closing behavior. Fixes #8446. --- src/components/menu/js/menuController.js | 3 +++ src/components/menu/js/menuDirective.js | 23 ++++++++++-------- src/components/menu/menu.spec.js | 31 +++++++++++++++--------- 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/components/menu/js/menuController.js b/src/components/menu/js/menuController.js index de1daf92c5e..53d19d649b9 100644 --- a/src/components/menu/js/menuController.js +++ b/src/components/menu/js/menuController.js @@ -195,6 +195,9 @@ function MenuController($mdMenu, $attrs, $element, $scope, $mdUtil, $timeout, $r } }; + // Expose the close method on the scope, allowing for use in the template. + $scope.$mdCloseMenu = this.close; + /** * Build a nice object out of our string attribute which specifies the * target mode for left and top positioning diff --git a/src/components/menu/js/menuDirective.js b/src/components/menu/js/menuDirective.js index f67a973e6db..53632e71317 100644 --- a/src/components/menu/js/menuDirective.js +++ b/src/components/menu/js/menuDirective.js @@ -12,7 +12,8 @@ * left in the DOM and is used to open the menu. This element is called the trigger element. * The trigger element's scope has access to `$mdOpenMenu($event)` * which it may call to open the menu. By passing $event as argument, the - * corresponding event is stopped from propagating up the DOM-tree. + * corresponding event is stopped from propagating up the DOM-tree. Similarly, `$mdCloseMenu()` + * can be used to close the menu. * * The second element is the `md-menu-content` element which represents the * contents of the menu when it is open. Typically this will contain `md-menu-item`s, @@ -105,7 +106,7 @@ * * ### Auto Focus * By default, when a menu opens, `md-menu` focuses the first button in the menu content. - * + * * But sometimes you would like to focus another specific menu item instead of the first.
* This can be done by applying the `md-autofocus` directive on the given element. * @@ -123,16 +124,18 @@ * Sometimes you would like to be able to click on a menu item without having the menu * close. To do this, ngMaterial exposes the `md-prevent-menu-close` attribute which * can be added to a button inside a menu to stop the menu from automatically closing. - * You can then close the menu programatically by injecting `$mdMenu` and calling - * `$mdMenu.hide()`. + * You can then close the menu either by using `$mdCloseMenu()` in the template, + * or programmatically by injecting `$mdMenu` and calling `$mdMenu.hide()`. * * - * - * - * - * Do Something - * - * + * + * + * + * + * Do Something + * + * + * * * * @usage diff --git a/src/components/menu/menu.spec.js b/src/components/menu/menu.spec.js index 57b74e35d4a..3cc2ad00b6c 100644 --- a/src/components/menu/menu.spec.js +++ b/src/components/menu/menu.spec.js @@ -66,8 +66,7 @@ describe('material.components.menu', function() { }); it('opens on click without $event', function() { - var noEvent = true; - var menu = setup('ng-click', noEvent); + var menu = setup('ng-click="$mdOpenMenu()"'); openMenu(menu); expect(getOpenMenuContainer(menu).length).toBe(1); closeMenu(menu); @@ -75,7 +74,7 @@ describe('material.components.menu', function() { }); it('opens on mouseEnter', function() { - var menu = setup('ng-mouseenter'); + var menu = setup('ng-mouseenter="$mdOpenMenu($event)"'); openMenu(menu, 'mouseenter'); expect(getOpenMenuContainer(menu).length).toBe(1); closeMenu(menu); @@ -83,8 +82,7 @@ describe('material.components.menu', function() { }); it('opens on mouseEnter without $event', function() { - var noEvent = true; - var menu = setup('ng-mouseenter', noEvent); + var menu = setup('ng-mouseenter="$mdOpenMenu()"'); openMenu(menu, 'mouseenter'); expect(getOpenMenuContainer(menu).length).toBe(1); closeMenu(menu); @@ -116,7 +114,7 @@ describe('material.components.menu', function() { it('should remove the backdrop if the container scope got destroyed', inject(function($document, $rootScope) { var scope = $rootScope.$new(); - var menu = setup(null, null, scope); + var menu = setup(null, scope); openMenu(menu); expect($document.find('md-backdrop').length).not.toBe(0); @@ -214,6 +212,18 @@ describe('material.components.menu', function() { expect(getOpenMenuContainer(menu).length).toBe(0); }); + it('closes via the scope method', function() { + var menu = setup('ng-mouseenter="$mdOpenMenu($event)" ng-mouseleave="$mdCloseMenu()"'); + + expect(getOpenMenuContainer(menu).length).toBe(0); + openMenu(menu, 'mouseenter'); + expect(getOpenMenuContainer(menu).length).toBe(1); + + menu.find('button').triggerHandler('mouseleave'); + waitForMenuClose(); + expect(getOpenMenuContainer(menu).length).toBe(0); + }); + itClosesWithAttributes([ 'data-ng-click', 'x-ng-click', 'ui-sref', 'data-ui-sref', 'x-ui-sref', @@ -226,7 +236,7 @@ describe('material.components.menu', function() { } function testAttribute(attr) { - return inject(function($rootScope, $compile, $timeout, $browser) { + return inject(function($rootScope, $compile, $timeout) { var template = '' + '' + ' ' + @@ -255,17 +265,17 @@ describe('material.components.menu', function() { } }); - function setup(triggerType, noEvent, scope) { + function setup(buttonAttrs, scope) { var menu, template = $mdUtil.supplant('' + '' + - ' ' + + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + - '',[ triggerType || 'ng-click', noEvent ? '' : "$event" ]); + '', [ buttonAttrs || 'ng-click="$mdOpenMenu($event)"' ]); inject(function($compile, $rootScope) { $rootScope.doSomething = function($event) { @@ -305,7 +315,6 @@ describe('material.components.menu', function() { function closeMenu() { inject(function($document) { - $document.find('md-backdrop'); $document.find('md-backdrop').triggerHandler('click'); waitForMenuClose(); });