mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-20 20:33:32 +08:00
refactor(menu): inject MenuController to control app menus
Menu has been improved to make it easier to open, close, toggle and enable menus. Instead of injecting `IonicApp` to find the menu component, you now inject `MenuController`. Was: ``` constructor(app: IonicApp) { this.app = app; } openMenu() { this.app.getComponent('leftMenu').close(); } ``` Now: To programmatically interact with any menu, you can inject the `MenuController` provider into any component or directive. This makes it easy get ahold of and control the correct menu instance. By default Ionic will find the app's menu without requiring a menu ID. An id attribute on an `<ion-menu>` is only required if there are multiple menus on the same side. If there are multiple menus, but on different sides, you can use the name of the side to get the correct menu If there's only one menu: ``` constructor(menu: MenuController) { this.menu = menu; } openMenu() { this.menu.close(); } ``` If there is a menu on the left and right side: ``` toggleMenu() { this.menu.toggle('left'); } ``` If there are multiple menus on the same side: ``` <ion-menu id="myMenuId" side="left">...</ion-menu> <ion-menu id="otherMenuId" side="left">...</ion-menu> closeMenu() { this.menu.close('myMenuId'); } ```
This commit is contained in:
@ -1,96 +1,15 @@
|
||||
import {Component, forwardRef, Directive, Host, EventEmitter, ElementRef, NgZone, Input, Output, Renderer} from 'angular2/core';
|
||||
|
||||
import {Ion} from '../ion';
|
||||
import {IonicApp} from '../app/app';
|
||||
import {Config} from '../../config/config';
|
||||
import {Platform} from '../../platform/platform';
|
||||
import {Keyboard} from '../../util/keyboard';
|
||||
import * as gestures from './menu-gestures';
|
||||
import {Gesture} from '../../gestures/gesture';
|
||||
import {MenuController} from './menu-controller';
|
||||
import {MenuType} from './menu-types';
|
||||
|
||||
|
||||
/**
|
||||
* @name Menu
|
||||
* @description
|
||||
* _For basic Menu usage, see the [Menu section](../../../../components/#menus)
|
||||
* of the Component docs._
|
||||
*
|
||||
* Menu is a side-menu navigation that can be dragged out or toggled to show.
|
||||
*
|
||||
* @usage
|
||||
* In order to use Menu, you must specify a [reference](https://angular.io/docs/ts/latest/guide/user-input.html#local-variables)
|
||||
* to the content element that Menu should listen on for drag events, using the `content` property:
|
||||
*
|
||||
* ```html
|
||||
* <ion-menu [content]="mycontent">
|
||||
* <ion-content>
|
||||
* <ion-list>
|
||||
* ...
|
||||
* </ion-list>
|
||||
* </ion-content>
|
||||
* </ion-menu>
|
||||
*
|
||||
* <ion-nav #mycontent [root]="rootPage"></ion-nav>
|
||||
* ```
|
||||
*
|
||||
* By default, Menus are on the left, but this can be overriden with the `side`
|
||||
* property:
|
||||
* ```html
|
||||
* <ion-menu [content]="mycontent" side="right"></ion-menu>
|
||||
* ```
|
||||
*
|
||||
* Menus can optionally be given an `id` attribute which allows the app to
|
||||
* to get ahold of menu references. If no `id` is given then the menu
|
||||
* automatically receives an `id` created from the side it is on, such as
|
||||
* `leftMenu` or `rightMenu`. When using more than one menu it is always
|
||||
* recommended to give each menu a unique `id`. Additionally menuToggle and
|
||||
* menuClose directives should be given menu id values of their respective
|
||||
* menu.
|
||||
*
|
||||
* Menu supports two display styles: overlay, and reveal. Overlay
|
||||
* is the traditional Android drawer style, and Reveal is the traditional iOS
|
||||
* style. By default, Menu will adjust to the correct style for the platform,
|
||||
* but this can be overriden using the `type` property:
|
||||
* ```html
|
||||
* <ion-menu [content]="mycontent" type="overlay"></ion-menu>
|
||||
* ```
|
||||
*
|
||||
* To programatically interact with the menu, you first get the menu component.
|
||||
*
|
||||
* ```ts
|
||||
* @Page({
|
||||
* `<ion-menu [content]="mycontent" id="leftMenu"></ion-menu>
|
||||
* <ion-nav #mycontent [root]="rootPage"></ion-nav>`
|
||||
* )}
|
||||
* export class MyClass{
|
||||
* constructor(app: IonicApp){
|
||||
* this.app = app;
|
||||
* this.menu;
|
||||
* }
|
||||
*
|
||||
* // Wait until the page is ready
|
||||
* ngAfterViewInit(){
|
||||
* this.menu = this.app.getComponent('leftMenu');
|
||||
* }
|
||||
*
|
||||
* // Open the menu programatically
|
||||
* openMenu(){
|
||||
* this.menu.open();
|
||||
* }
|
||||
*
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* If you want to use any of the APIs down below, make sure to grabe the menu component by it's ID
|
||||
*
|
||||
* @demo /docs/v2/demos/menu/
|
||||
*
|
||||
* @see {@link /docs/v2/components#menus Menu Component Docs}
|
||||
* @see {@link /docs/v2/components#navigation Navigation Component Docs}
|
||||
* @see {@link ../../nav/Nav Nav API Docs}
|
||||
*
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ion-menu',
|
||||
host: {
|
||||
@ -159,7 +78,7 @@ export class Menu extends Ion {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@Input() swipeEnabled: string;
|
||||
@Input() swipeEnabled: any;
|
||||
|
||||
/**
|
||||
* @private
|
||||
@ -172,9 +91,9 @@ export class Menu extends Ion {
|
||||
@Output() opening: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
constructor(
|
||||
private _menuCtrl: MenuController,
|
||||
private _elementRef: ElementRef,
|
||||
private _config: Config,
|
||||
private _app: IonicApp,
|
||||
private _platform: Platform,
|
||||
private _renderer: Renderer,
|
||||
private _keyboard: Keyboard,
|
||||
@ -204,15 +123,7 @@ export class Menu extends Ion {
|
||||
self.isSwipeEnabled = false;
|
||||
}
|
||||
|
||||
if (!self.id) {
|
||||
// Auto register
|
||||
self.id = self.side + 'Menu';
|
||||
if (self._app.getComponent(self.id)) {
|
||||
// id already exists, make sure this one is unique
|
||||
self.id += (++menuIds);
|
||||
}
|
||||
self._app.register(self.id, self);
|
||||
}
|
||||
this._menuCtrl.register(self);
|
||||
|
||||
self._initGesture();
|
||||
self._initType(self.type);
|
||||
@ -232,7 +143,7 @@ export class Menu extends Ion {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_initGesture() {
|
||||
private _initGesture() {
|
||||
this._zone.runOutsideAngular(() => {
|
||||
switch(this.side) {
|
||||
case 'right':
|
||||
@ -250,7 +161,7 @@ export class Menu extends Ion {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_initType(type) {
|
||||
private _initType(type) {
|
||||
type = type && type.trim().toLowerCase();
|
||||
if (!type) {
|
||||
type = this._config.get('menuType');
|
||||
@ -262,9 +173,9 @@ export class Menu extends Ion {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_getType() {
|
||||
private _getType() {
|
||||
if (!this._type) {
|
||||
this._type = new menuTypes[this.type](this);
|
||||
this._type = MenuController.create(this.type, this);
|
||||
|
||||
if (this._config.get('animate') === false) {
|
||||
this._type.open.duration(33);
|
||||
@ -333,7 +244,7 @@ export class Menu extends Ion {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_before() {
|
||||
private _before() {
|
||||
// this places the menu into the correct location before it animates in
|
||||
// this css class doesn't actually kick off any animations
|
||||
if (this.isEnabled) {
|
||||
@ -348,7 +259,7 @@ export class Menu extends Ion {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_after(isOpen) {
|
||||
private _after(isOpen) {
|
||||
// keep opening/closing the menu disabled for a touch more yet
|
||||
// only add listeners/css if it's enabled and isOpen
|
||||
// and only remove listeners/css if it's not open
|
||||
@ -374,7 +285,7 @@ export class Menu extends Ion {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_prevent() {
|
||||
private _prevent() {
|
||||
// used to prevent unwanted opening/closing after swiping open/close
|
||||
// or swiping open the menu while pressing down on the menuToggle
|
||||
this._preventTime = Date.now() + 20;
|
||||
@ -383,7 +294,7 @@ export class Menu extends Ion {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_isPrevented() {
|
||||
private _isPrevented() {
|
||||
return this._preventTime > Date.now();
|
||||
}
|
||||
|
||||
@ -417,7 +328,7 @@ export class Menu extends Ion {
|
||||
* @param {boolean} shouldEnable True if it should be enabled, false if not.
|
||||
* @return {Menu} Returns the instance of the menu, which is useful for chaining.
|
||||
*/
|
||||
enable(shouldEnable) {
|
||||
enable(shouldEnable: boolean) {
|
||||
this.isEnabled = shouldEnable;
|
||||
if (!shouldEnable && this.isOpen) {
|
||||
this.close();
|
||||
@ -430,7 +341,7 @@ export class Menu extends Ion {
|
||||
* @param {boolean} shouldEnable True if it should be swipe-able, false if not.
|
||||
* @return {Menu} Returns the instance of the menu, which is useful for chaining.
|
||||
*/
|
||||
swipeEnable(shouldEnable) {
|
||||
swipeEnable(shouldEnable: boolean) {
|
||||
this.isSwipeEnabled = shouldEnable;
|
||||
return this;
|
||||
}
|
||||
@ -456,53 +367,19 @@ export class Menu extends Ion {
|
||||
return this.backdrop.elementRef.nativeElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
static register(name: string, cls: new(...args: any[]) => MenuType) {
|
||||
menuTypes[name] = cls;
|
||||
}
|
||||
//static register(name:string , cls: typeof MenuType) {
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ngOnDestroy() {
|
||||
this._app.unregister(this.id);
|
||||
this._menuCtrl.unregister(this);
|
||||
this._gesture && this._gesture.destroy();
|
||||
this._targetGesture && this._targetGesture.destroy();
|
||||
this._type && this._type.ngOnDestroy();
|
||||
this._cntEle = null;
|
||||
}
|
||||
|
||||
static getById(app, menuId) {
|
||||
let menu = null;
|
||||
|
||||
if (menuId) {
|
||||
menu = app.getComponent(menuId);
|
||||
if (!menu) {
|
||||
console.error('Menu with id "' + menuId + '" cannot be found for menuToggle');
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
menu = app.getComponent('leftMenu');
|
||||
if (!menu) {
|
||||
menu = app.getComponent('rightMenu');
|
||||
}
|
||||
if (!menu) {
|
||||
console.error('Menu with id "leftMenu" or "rightMenu" cannot be found for menuToggle');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let menuTypes:{ [name: string]: new(...args: any[]) => MenuType } = {};
|
||||
let menuIds:number = 0;
|
||||
|
||||
|
||||
/**
|
||||
@ -511,22 +388,22 @@ let menuIds:number = 0;
|
||||
@Directive({
|
||||
selector: '.backdrop',
|
||||
host: {
|
||||
'(click)': 'clicked($event)'
|
||||
'(click)': 'clicked($event)',
|
||||
}
|
||||
})
|
||||
export class MenuBackdrop {
|
||||
|
||||
constructor(@Host() private menu: Menu, public elementRef: ElementRef) {
|
||||
menu.backdrop = this;
|
||||
constructor(@Host() private _menuCtrl: Menu, public elementRef: ElementRef) {
|
||||
_menuCtrl.backdrop = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
clicked(ev) {
|
||||
console.debug('backdrop clicked')
|
||||
private clicked(ev) {
|
||||
console.debug('backdrop clicked');
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
this.menu.close();
|
||||
this._menuCtrl.close();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user