diff --git a/ionic/components/loading/loading.ts b/ionic/components/loading/loading.ts index 2024d35654..7c7f39f134 100644 --- a/ionic/components/loading/loading.ts +++ b/ionic/components/loading/loading.ts @@ -99,10 +99,12 @@ export class Loading extends ViewController { constructor(opts: LoadingOptions = {}) { opts.showBackdrop = isPresent(opts.showBackdrop) ? !!opts.showBackdrop : true; + opts.dismissOnPageChange = isPresent(opts.dismissOnPageChange) ? !!opts.dismissOnPageChange : false; super(LoadingCmp, opts); this.viewType = 'loading'; this.isOverlay = true; + this.usePortal = true; // by default, loading indicators should not fire lifecycle events of other views // for example, when an loading indicators enters, the current active view should diff --git a/ionic/components/nav/nav-controller.ts b/ionic/components/nav/nav-controller.ts index 4e3477006b..e91ebaadb3 100644 --- a/ionic/components/nav/nav-controller.ts +++ b/ionic/components/nav/nav-controller.ts @@ -8,6 +8,7 @@ import {Keyboard} from '../../util/keyboard'; import {NavParams} from './nav-params'; import {NavRouter} from './nav-router'; import {pascalCaseToDashCase, isTrueProperty, isBlank} from '../../util/util'; +import {Portal} from './nav-portal'; import {raf} from '../../util/dom'; import {SwipeBackGesture} from './swipe-back'; import {Transition} from '../../transitions/transition'; @@ -109,6 +110,7 @@ export class NavController extends Ion { private _trans: Transition; private _sbGesture: SwipeBackGesture; private _sbThreshold: number; + private _portal: Portal; protected _sbEnabled: boolean; protected _ids: number = -1; @@ -170,6 +172,10 @@ export class NavController extends Ion { provide(NavController, {useValue: this}) ]); } + + setPortal(val: Portal) { + this._portal = val; + } /** * Set the root for the current navigation stack @@ -412,7 +418,7 @@ export class NavController extends Ion { if (rootNav['_tabs']) { // TODO: must have until this goes in // https://github.com/angular/angular/issues/5481 - console.error('A parent is required for ActionSheet/Alert/Modal'); + console.error('A parent is required for ActionSheet/Alert/Modal/Loading'); return; } @@ -433,7 +439,12 @@ export class NavController extends Ion { keyboardClose: false, direction: 'back', animation: enteringView.getTransitionName('back') - }); + }); + + if (enteringView.usePortal && this._portal) { + this._portal.present(enteringView); + return; + } // start the transition return rootNav._insertViews(-1, [enteringView], opts); @@ -534,7 +545,7 @@ export class NavController extends Ion { if (this._views[i] === enteringView) { // cool, so the last valid view is also our entering view!! - // this means we should animate that bad boy in so its the active view + // this means we should animate that bad boy in so it's the active view // return a promise and resolve when the transition has completed // get the leaving view which the _insert() already set @@ -730,8 +741,8 @@ export class NavController extends Ion { // get the view thats ready to enter let enteringView = this.getByState(STATE_INIT_ENTER); - if (!enteringView) { - // oh knows! no entering view to go to! + if (!enteringView && this._portal) { + // oh nos! no entering view to go to! // if there is no previous view that would enter in this nav stack // and the option is set to climb up the nav parent looking // for the next nav we could transition to instead @@ -1248,6 +1259,14 @@ export class NavController extends Ion { // see if we should add the swipe back gesture listeners or not this._sbCheck(); + + if (this._portal) { + this._portal._views.forEach(view => { + if (view.data && view.data.dismissOnPageChange) { + view.dismiss(); + } + }); + } } else { // darn, so this wasn't the most recent transition @@ -1640,7 +1659,7 @@ export class NavController extends Ion { } else { // this is the initial view - enteringView.setZIndex(INIT_ZINDEX, this._renderer); + enteringView.setZIndex(this._portal ? INIT_ZINDEX : PORTAL_ZINDEX, this._renderer); } } else if (direction === 'back') { @@ -1680,5 +1699,6 @@ const STATE_REMOVE = 'remove'; const STATE_REMOVE_AFTER_TRANS = 'remove_after_trans'; const STATE_FORCE_ACTIVE = 'force_active'; const INIT_ZINDEX = 100; +const PORTAL_ZINDEX = 9999; let ctrlIds = -1; diff --git a/ionic/components/nav/nav-portal.ts b/ionic/components/nav/nav-portal.ts new file mode 100644 index 0000000000..6e6786ab4a --- /dev/null +++ b/ionic/components/nav/nav-portal.ts @@ -0,0 +1,30 @@ +import {Directive, ElementRef, Input, Optional, NgZone, Compiler, AppViewManager, Renderer, Type, ContentChild} from 'angular2/core'; + +import {IonicApp} from '../app/app'; +import {Config} from '../../config/config'; +import {Keyboard} from '../../util/keyboard'; +import {NavController} from './nav-controller'; +import {ViewController} from './view-controller'; + +/** + * @private + */ +@Directive({ + selector: '[portal]' +}) +export class Portal extends NavController { + constructor( + @Optional() hostNavCtrl: NavController, + @Optional() viewCtrl: ViewController, + app: IonicApp, + config: Config, + keyboard: Keyboard, + elementRef: ElementRef, + compiler: Compiler, + viewManager: AppViewManager, + zone: NgZone, + renderer: Renderer + ) { + super(hostNavCtrl, app, config, keyboard, elementRef, null, compiler, viewManager, zone, renderer); + } +} diff --git a/ionic/components/nav/nav.ts b/ionic/components/nav/nav.ts index 86ceb92549..b808f57dcb 100644 --- a/ionic/components/nav/nav.ts +++ b/ionic/components/nav/nav.ts @@ -1,10 +1,11 @@ -import {Component, ElementRef, Input, Optional, NgZone, Compiler, AppViewManager, Renderer, Type} from 'angular2/core'; +import {Component, ElementRef, Input, Optional, NgZone, Compiler, AppViewManager, Renderer, Type, ViewChild} from 'angular2/core'; import {IonicApp} from '../app/app'; import {Config} from '../../config/config'; import {Keyboard} from '../../util/keyboard'; import {isTrueProperty} from '../../util/util'; import {NavController} from './nav-controller'; +import {Portal} from './nav-portal'; import {ViewController} from './view-controller'; /** @@ -104,7 +105,8 @@ import {ViewController} from './view-controller'; */ @Component({ selector: 'ion-nav', - template: '
' + template: '
', + directives: [Portal] }) export class Nav extends NavController { private _root: Type; @@ -172,5 +174,9 @@ export class Nav extends NavController { this.push(this._root); } } - + + @ViewChild(Portal) + private set _navPortal(val: Portal) { + this.setPortal(val); + } } diff --git a/ionic/components/nav/test/nav-controller.spec.ts b/ionic/components/nav/test/nav-controller.spec.ts index 7a960b1288..7c7bcbb0ce 100644 --- a/ionic/components/nav/test/nav-controller.spec.ts +++ b/ionic/components/nav/test/nav-controller.spec.ts @@ -1236,6 +1236,8 @@ export function run() { setElementClass: function(){}, setElementStyle: function(){} }; + + nav._portal = new NavController(null, null, config, null, elementRef, null, null, null, null, null); return nav; } diff --git a/ionic/components/nav/view-controller.ts b/ionic/components/nav/view-controller.ts index b974b69fde..30b1f11e7a 100644 --- a/ionic/components/nav/view-controller.ts +++ b/ionic/components/nav/view-controller.ts @@ -77,6 +77,11 @@ export class ViewController { */ isOverlay: boolean = false; + /** + * @private + */ + usePortal: boolean = false; + /** * @private */