refactor(nav-controller-base): cleanup some logic

NavControllerBase is the core of ionic 2 navigation. It handles all the transitions and it is complicated code to follow.
I am refactoring it to allow future developers and contributors to follow it better.

!node.parent now becomes node.isRoot()

ViewController does not remove itself from the stack, but two new auxiliar function in nav controller: _insertView() and _removeView() are used to add a view to the stack.

And so on...

All e2e and unit tests passing...
This commit is contained in:
Manu Mtz.-Almeida
2016-10-18 16:22:49 +02:00
parent ff1f340285
commit d9e8b1bec6
8 changed files with 173 additions and 162 deletions

View File

@ -34,6 +34,7 @@ export class Animation {
parent: Animation; parent: Animation;
opts: AnimationOptions; opts: AnimationOptions;
hasChildren: boolean = false;
isPlaying: boolean = false; isPlaying: boolean = false;
hasCompleted: boolean = false; hasCompleted: boolean = false;
@ -81,6 +82,7 @@ export class Animation {
*/ */
add(childAnimation: Animation): Animation { add(childAnimation: Animation): Animation {
childAnimation.parent = this; childAnimation.parent = this;
this.hasChildren = true;
this._cL = (this._c = this._c || []).push(childAnimation); this._cL = (this._c = this._c || []).push(childAnimation);
return this; return this;
} }

View File

@ -298,14 +298,14 @@ export class Tab extends NavControllerBase {
/** /**
* @private * @private
*/ */
_viewInsert(viewCtrl: ViewController, componentRef: ComponentRef<any>, viewport: ViewContainerRef) { _viewAttachToDOM(viewCtrl: ViewController, componentRef: ComponentRef<any>, viewport: ViewContainerRef) {
const isTabSubPage = (this.parent._subPages && viewCtrl.index > 0); const isTabSubPage = (this.parent._subPages && viewCtrl.index > 0);
if (isTabSubPage) { if (isTabSubPage) {
viewport = this.parent.portal; viewport = this.parent.portal;
} }
super._viewInsert(viewCtrl, componentRef, viewport); super._viewAttachToDOM(viewCtrl, componentRef, viewport);
if (isTabSubPage) { if (isTabSubPage) {
// add the .tab-subpage css class to tabs pages that should act like subpages // add the .tab-subpage css class to tabs pages that should act like subpages

View File

@ -193,9 +193,11 @@ export class NavControllerBase extends Ion implements NavController {
while (trns) { while (trns) {
if (trns.enteringView && (trns.enteringView._state !== ViewState.LOADED)) { if (trns.enteringView && (trns.enteringView._state !== ViewState.LOADED)) {
// destroy the entering views and all of their hopes and dreams // destroy the entering views and all of their hopes and dreams
trns.enteringView._destroy(this._renderer); this._destroyView(trns.enteringView);
}
if (!trns.parent) {
break;
} }
if (!trns.parent) break;
} }
if (trns) { if (trns) {
@ -253,6 +255,8 @@ export class NavControllerBase extends Ion implements NavController {
const leavingView = this.getActive(); const leavingView = this.getActive();
const enteringView = this._getEnteringView(ti, leavingView); const enteringView = this._getEnteringView(ti, leavingView);
assert(leavingView || enteringView, 'Both leavingView and enteringView are null');
// Initialize enteringView // Initialize enteringView
if (enteringView && isBlank(enteringView._state)) { if (enteringView && isBlank(enteringView._state)) {
// render the entering view, and all child navs and views // render the entering view, and all child navs and views
@ -327,17 +331,23 @@ export class NavControllerBase extends Ion implements NavController {
const opts = ti.opts || {}; const opts = ti.opts || {};
const insertViews = ti.insertViews; const insertViews = ti.insertViews;
const removeStart = ti.removeStart; const removeStart = ti.removeStart;
let view;
let destroyQueue: ViewController[] = []; let destroyQueue: ViewController[] = [];
// there are views to remove
if (isPresent(removeStart)) { if (isPresent(removeStart)) {
for (var i = 0; i < ti.removeCount; i++) { for (var i = 0; i < ti.removeCount; i++) {
destroyQueue.push(this._views[i + removeStart]); view = this._views[i + removeStart];
assert(view, 'internal error, view in destroyQueue can not be null');
if (view && view !== enteringView && view !== leavingView) {
destroyQueue.push(view);
}
} }
// default the direction to "back" // default the direction to "back"
opts.direction = opts.direction || DIRECTION_BACK; opts.direction = opts.direction || DIRECTION_BACK;
} }
// there are views to insert
if (insertViews) { if (insertViews) {
// manually set the new view's id if an id was passed in the options // manually set the new view's id if an id was passed in the options
if (isPresent(opts.id)) { if (isPresent(opts.id)) {
@ -346,25 +356,8 @@ export class NavControllerBase extends Ion implements NavController {
// add the views to the // add the views to the
for (var i = 0; i < insertViews.length; i++) { for (var i = 0; i < insertViews.length; i++) {
var view = insertViews[i]; view = insertViews[i];
this._insertViewAt(view, ti.insertStart + i);
var existingIndex = this._views.indexOf(view);
if (existingIndex > -1) {
// this view is already in the stack!!
// move it to its new location
this._views.splice(ti.insertStart + i, 0, this._views.splice(existingIndex, 1)[0]);
} else {
// this is a new view to add to the stack
// create the new entering view
view._setNav(this);
// give this inserted view an ID
view.id = this.id + '-' + (++this._ids);
// insert the entering view into the correct index in the stack
this._views.splice(ti.insertStart + i, 0, view);
}
} }
if (ti.enteringRequiresTransition) { if (ti.enteringRequiresTransition) {
@ -372,27 +365,20 @@ export class NavControllerBase extends Ion implements NavController {
opts.direction = opts.direction || DIRECTION_FORWARD; opts.direction = opts.direction || DIRECTION_FORWARD;
} }
} }
// if the views to be removed are in the beginning or middle // if the views to be removed are in the beginning or middle
// and there is not a view that needs to visually transition out // and there is not a view that needs to visually transition out
// then just destroy them and don't transition anything // then just destroy them and don't transition anything
for (var i = 0; i < destroyQueue.length; i++) { // batch all of lifecycles together
// batch all of lifecycles together for (view of destroyQueue) {
var view = destroyQueue[i]; this._willLeave(view);
if (view && view !== enteringView && view !== leavingView) { this._didLeave(view);
this._willLeave(view); this._willUnload(view);
this._didLeave(view);
this._willUnload(view);
}
} }
for (var i = 0; i < destroyQueue.length; i++) {
// batch all of the destroys together // once all lifecycle events has been delivered, we can safely detroy the views
var view = destroyQueue[i]; for (view of destroyQueue) {
if (view && view !== enteringView && view !== leavingView) { this._destroyView(view);
view._destroy(this._renderer);
}
} }
destroyQueue.length = 0;
if (ti.enteringRequiresTransition || ti.leavingRequiresTransition && enteringView !== leavingView) { if (ti.enteringRequiresTransition || ti.leavingRequiresTransition && enteringView !== leavingView) {
// set which animation it should use if it wasn't set yet // set which animation it should use if it wasn't set yet
@ -434,6 +420,27 @@ export class NavControllerBase extends Ion implements NavController {
this._willLoad(enteringView); this._willLoad(enteringView);
} }
_viewAttachToDOM(view: ViewController, componentRef: ComponentRef<any>, viewport: ViewContainerRef) {
// successfully finished loading the entering view
// fire off the "didLoad" lifecycle events
this._didLoad(view);
// render the component ref instance to the DOM
// ******** DOM WRITE ****************
viewport.insert(componentRef.hostView, viewport.length);
view._state = ViewState.PRE_RENDERED;
if (view._cssClass) {
// the ElementRef of the actual ion-page created
var pageElement = componentRef.location.nativeElement;
// ******** DOM WRITE ****************
this._renderer.setElementClass(pageElement, view._cssClass, true);
}
componentRef.changeDetectorRef.detectChanges();
}
_viewTest(enteringView: ViewController, leavingView: ViewController, ti: TransitionInstruction) { _viewTest(enteringView: ViewController, leavingView: ViewController, ti: TransitionInstruction) {
const promises: Promise<any>[] = []; const promises: Promise<any>[] = [];
const reject = ti.reject; const reject = ti.reject;
@ -442,47 +449,38 @@ export class NavControllerBase extends Ion implements NavController {
if (leavingView) { if (leavingView) {
const leavingTestResult = leavingView._lifecycleTest('Leave'); const leavingTestResult = leavingView._lifecycleTest('Leave');
if (isPresent(leavingTestResult) && leavingTestResult !== true) { if (leavingTestResult === false) {
if (leavingTestResult instanceof Promise) { // synchronous reject
// async promise reject((leavingTestResult !== false ? leavingTestResult : `ionViewCanLeave rejected`));
promises.push(leavingTestResult); return false;
} else if (leavingTestResult instanceof Promise) {
} else { // async promise
// synchronous reject promises.push(leavingTestResult);
reject((leavingTestResult !== false ? leavingTestResult : `ionViewCanLeave rejected`));
return false;
}
} }
} }
if (enteringView) { if (enteringView) {
const enteringTestResult = enteringView._lifecycleTest('Enter'); const enteringTestResult = enteringView._lifecycleTest('Enter');
if (isPresent(enteringTestResult) && enteringTestResult !== true) { if (enteringTestResult === false) {
if (enteringTestResult instanceof Promise) { // synchronous reject
// async promise reject((enteringTestResult !== false ? enteringTestResult : `ionViewCanEnter rejected`));
promises.push(enteringTestResult); return false;
} else if (enteringTestResult instanceof Promise) {
} else { // async promise
// synchronous reject promises.push(enteringTestResult);
reject((enteringTestResult !== false ? enteringTestResult : `ionViewCanEnter rejected`));
return false;
}
} }
} }
if (promises.length) { if (promises.length) {
// darn, async promises, gotta wait for them to resolve // darn, async promises, gotta wait for them to resolve
Promise.all(promises).then(() => { Promise.all(promises)
// all promises resolved! let's continue .then(() => this._postViewInit(enteringView, leavingView, ti, resolve))
this._postViewInit(enteringView, leavingView, ti, resolve); .catch(reject);
} else {
}).catch(reject); // synchronous and all tests passed! let's move on already
return true; this._postViewInit(enteringView, leavingView, ti, resolve);
} }
// synchronous and all tests passed! let's move on already
this._postViewInit(enteringView, leavingView, ti, resolve);
return true; return true;
} }
@ -508,27 +506,21 @@ export class NavControllerBase extends Ion implements NavController {
// create the transition animation from the TransitionController // create the transition animation from the TransitionController
// this will either create the root transition, or add it as a child transition // this will either create the root transition, or add it as a child transition
const trns = this._trnsCtrl.get(this._trnsId, enteringView, leavingView, animationOpts); const transition = this._trnsCtrl.get(this._trnsId, enteringView, leavingView, animationOpts);
// ensure any swipeback transitions are cleared out // ensure any swipeback transitions are cleared out
this._sbTrns && this._sbTrns.destroy(); this._sbTrns && this._sbTrns.destroy();
this._sbTrns = null;
if (trns.parent) { // swipe to go back root transition
// this is important for later to know if there if (transition.isRoot() && opts.progressAnimation) {
// are any more child tests to check for this._sbTrns = transition;
trns.parent.hasChildTrns = true;
} else {
// this is the root transition
if (opts.progressAnimation) {
this._sbTrns = trns;
}
} }
trns.registerStart(() => { transition.registerStart(() => {
this._trnsStart(trns, enteringView, leavingView, opts, resolve); this._trnsStart(transition, enteringView, leavingView, opts, resolve);
if (trns.parent) { if (transition.parent) {
trns.parent.start(); transition.parent.start();
} }
}); });
@ -537,37 +529,16 @@ export class NavControllerBase extends Ion implements NavController {
// this would also render new child navs/views // this would also render new child navs/views
// which may have their very own async canEnter/Leave tests // which may have their very own async canEnter/Leave tests
// ******** DOM WRITE **************** // ******** DOM WRITE ****************
this._viewInsert(enteringView, enteringView._cmp, this._viewport); this._viewAttachToDOM(enteringView, enteringView._cmp, this._viewport);
} }
if (!trns.hasChildTrns) { if (!transition.hasChildren) {
// lowest level transition, so kick it off and let it bubble up to start all of them // lowest level transition, so kick it off and let it bubble up to start all of them
trns.start(); transition.start();
} }
} }
_viewInsert(view: ViewController, componentRef: ComponentRef<any>, viewport: ViewContainerRef) { _trnsStart(transition: Transition, enteringView: ViewController, leavingView: ViewController, opts: NavOptions, resolve: TransitionResolveFn) {
// successfully finished loading the entering view
// fire off the "didLoad" lifecycle events
this._didLoad(view);
// render the component ref instance to the DOM
// ******** DOM WRITE ****************
viewport.insert(componentRef.hostView, viewport.length);
view._state = ViewState.PRE_RENDERED;
if (view._cssClass) {
// the ElementRef of the actual ion-page created
var pageElement = componentRef.location.nativeElement;
// ******** DOM WRITE ****************
this._renderer.setElementClass(pageElement, view._cssClass, true);
}
componentRef.changeDetectorRef.detectChanges();
}
_trnsStart(trns: Transition, enteringView: ViewController, leavingView: ViewController, opts: NavOptions, resolve: TransitionResolveFn) {
this._trnsId = null; this._trnsId = null;
// set the correct zIndex for the entering and leaving views // set the correct zIndex for the entering and leaving views
@ -578,43 +549,46 @@ export class NavControllerBase extends Ion implements NavController {
// ******** DOM WRITE **************** // ******** DOM WRITE ****************
enteringView && enteringView._domShow(true, this._renderer); enteringView && enteringView._domShow(true, this._renderer);
if (leavingView) { // always ensure the leaving view is viewable
// always ensure the leaving view is viewable // ******** DOM WRITE ****************
// ******** DOM WRITE **************** leavingView && leavingView._domShow(true, this._renderer);
leavingView._domShow(true, this._renderer);
}
// initialize the transition // initialize the transition
trns.init(); transition.init();
if ((!this._init && this._views.length === 1 && !this._isPortal) || this.config.get('animate') === false) { // we should animate (duration > 0) if the pushed page is not the first one (startup)
// the initial load shouldn't animate, unless it's a portal // or if it is a portal (modal, actionsheet, etc.)
let isFirstPage = !this._init && this._views.length === 1;
let shouldNotAnimate = isFirstPage && !this._isPortal;
let canNotAnimate = this.config.get('animate') === false;
if (shouldNotAnimate || canNotAnimate) {
opts.animate = false; opts.animate = false;
} }
if (opts.animate === false) { if (opts.animate === false) {
// if it was somehow set to not animation, then make the duration zero // if it was somehow set to not animation, then make the duration zero
trns.duration(0); transition.duration(0);
} }
// create a callback that needs to run within zone // create a callback that needs to run within zone
// that will fire off the willEnter/Leave lifecycle events at the right time // that will fire off the willEnter/Leave lifecycle events at the right time
trns.beforeAddRead(() => { transition.beforeAddRead(() => {
this._zone.run(this._viewsWillLifecycles.bind(this, enteringView, leavingView)); this._zone.run(this._viewsWillLifecycles.bind(this, enteringView, leavingView));
}); });
// create a callback for when the animation is done // create a callback for when the animation is done
trns.onFinish(() => { transition.onFinish(() => {
// transition animation has ended // transition animation has ended
this._zone.run(this._trnsFinish.bind(this, trns, opts, resolve)); this._zone.run(this._trnsFinish.bind(this, transition, opts, resolve));
}); });
// get the set duration of this transition // get the set duration of this transition
const duration = trns.getDuration(); const duration = transition.getDuration();
// set that this nav is actively transitioning // set that this nav is actively transitioning
this.setTransitioning(true, duration); this.setTransitioning(true, duration);
if (!trns.parent) { if (transition.isRoot()) {
// this is the top most, or only active transition, so disable the app // this is the top most, or only active transition, so disable the app
// add XXms to the duration the app is disabled when the keyboard is open // add XXms to the duration the app is disabled when the keyboard is open
@ -622,19 +596,21 @@ export class NavControllerBase extends Ion implements NavController {
// if this transition has a duration and this is the root transition // if this transition has a duration and this is the root transition
// then set that the app is actively disabled // then set that the app is actively disabled
this._app.setEnabled(false, duration + ACTIVE_TRANSITION_OFFSET); this._app.setEnabled(false, duration + ACTIVE_TRANSITION_OFFSET);
} else {
console.debug('transition is running but app has not been disabled');
} }
// cool, let's do this, start the transition // cool, let's do this, start the transition
if (opts.progressAnimation) { if (opts.progressAnimation) {
// this is a swipe to go back, just get the transition progress ready // this is a swipe to go back, just get the transition progress ready
// kick off the swipe animation start // kick off the swipe animation start
trns.progressStart(); transition.progressStart();
} else { } else {
// only the top level transition should actually start "play" // only the top level transition should actually start "play"
// kick it off and let it play through // kick it off and let it play through
// ******** DOM WRITE **************** // ******** DOM WRITE ****************
trns.play(); transition.play();
} }
} }
} }
@ -645,32 +621,30 @@ export class NavControllerBase extends Ion implements NavController {
leavingView && this._willLeave(leavingView); leavingView && this._willLeave(leavingView);
} }
_trnsFinish(trns: Transition, opts: NavOptions, resolve: TransitionResolveFn) { _trnsFinish(transition: Transition, opts: NavOptions, resolve: TransitionResolveFn) {
const hasCompleted = trns.hasCompleted;
// mainly for testing // mainly for testing
let enteringName: string; let enteringName: string;
let leavingName: string; let leavingName: string;
if (hasCompleted) { if (transition.hasCompleted) {
// transition has completed (went from 0 to 1) // transition has completed (went from 0 to 1)
if (trns.enteringView) { if (transition.enteringView) {
enteringName = trns.enteringView.name; enteringName = transition.enteringView.name;
this._didEnter(trns.enteringView); this._didEnter(transition.enteringView);
} }
if (trns.leavingView) { if (transition.leavingView) {
leavingName = trns.leavingView.name; leavingName = transition.leavingView.name;
this._didLeave(trns.leavingView); this._didLeave(transition.leavingView);
} }
this._cleanup(trns.enteringView); this._cleanup(transition.enteringView);
} }
if (!trns.parent) { if (transition.isRoot()) {
// this is the root transition // this is the root transition
// it's save to destroy this transition // it's save to destroy this transition
this._trnsCtrl.destroy(trns.trnsId); this._trnsCtrl.destroy(transition.trnsId);
// it's safe to enable the app again // it's safe to enable the app again
this._app.setEnabled(true); this._app.setEnabled(true);
@ -681,7 +655,7 @@ export class NavControllerBase extends Ion implements NavController {
this._linker.navChange(opts.direction); this._linker.navChange(opts.direction);
} }
if (opts.keyboardClose !== false && this._keyboard.isOpen()) { if (opts.keyboardClose !== false) {
// the keyboard is still open! // the keyboard is still open!
// no problem, let's just close for them // no problem, let's just close for them
this._keyboard.close(); this._keyboard.close();
@ -689,7 +663,40 @@ export class NavControllerBase extends Ion implements NavController {
} }
// congrats, we did it! // congrats, we did it!
resolve(hasCompleted, true, enteringName, leavingName, opts.direction); resolve(transition.hasCompleted, true, enteringName, leavingName, opts.direction);
}
_insertViewAt(view: ViewController, index: number) {
var existingIndex = this._views.indexOf(view);
if (existingIndex > -1) {
// this view is already in the stack!!
// move it to its new location
this._views.splice(index, 0, this._views.splice(existingIndex, 1)[0]);
} else {
// this is a new view to add to the stack
// create the new entering view
view._setNav(this);
// give this inserted view an ID
view.id = this.id + '-' + (++this._ids);
// insert the entering view into the correct index in the stack
this._views.splice(index, 0, view);
}
}
_removeView(view: ViewController) {
const views = this._views;
const index = views.indexOf(view);
if (index > -1) {
views.splice(index, 1);
}
}
_destroyView(view: ViewController) {
view._destroy(this._renderer);
this._removeView(view);
} }
/** /**
@ -707,7 +714,7 @@ export class NavControllerBase extends Ion implements NavController {
// this view comes after the active view // this view comes after the active view
// let's unload it // let's unload it
this._willUnload(view); this._willUnload(view);
view._destroy(this._renderer); this._destroyView(view);
} else if (i < activeViewIndex && !this._isPortal) { } else if (i < activeViewIndex && !this._isPortal) {
// this view comes before the active view // this view comes before the active view
@ -800,9 +807,10 @@ export class NavControllerBase extends Ion implements NavController {
} }
destroy() { destroy() {
for (var i = this._views.length - 1; i >= 0; i--) { let view;
this._views[i]._willUnload(); for (view of this._views) {
this._views[i]._destroy(this._renderer); view._willUnload();
view._destroy(this._renderer);
} }
this._views.length = 0; this._views.length = 0;

View File

@ -528,26 +528,25 @@ export class ViewController {
this._cmp.destroy(); this._cmp.destroy();
} }
if (this._nav) {
// remove it from the nav
const index = this._nav.indexOf(this);
if (index > -1) {
this._nav._views.splice(index, 1);
}
}
this._nav = this._cmp = this.instance = this._cntDir = this._cntRef = this._hdrDir = this._ftrDir = this._nb = this._onWillDismiss = null; this._nav = this._cmp = this.instance = this._cntDir = this._cntRef = this._hdrDir = this._ftrDir = this._nb = this._onWillDismiss = null;
} }
/** /**
* @private * @private
*/ */
_lifecycleTest(lifecycle: string): boolean | string | Promise<any> { _lifecycleTest(lifecycle: string): boolean | Promise<any> {
let instance = this.instance; let instance = this.instance;
let methodName = 'ionViewCan' + lifecycle; let methodName = 'ionViewCan' + lifecycle;
if (instance && instance[methodName]) { if (instance && instance[methodName]) {
try { try {
return instance[methodName](); let result = instance[methodName]();
if (result === false) {
return false;
} else if (result instanceof Promise) {
return result;
} else {
return true;
}
} catch (e) { } catch (e) {
console.error(`${this.name} ${methodName} error: ${e.message}`); console.error(`${this.name} ${methodName} error: ${e.message}`);
@ -572,7 +571,6 @@ export class ViewController {
} }
export function isViewController(viewCtrl: any) { export function isViewController(viewCtrl: any) {
return !!(viewCtrl && (<ViewController>viewCtrl)._didLoad && (<ViewController>viewCtrl)._willUnload); return !!(viewCtrl && (<ViewController>viewCtrl)._didLoad && (<ViewController>viewCtrl)._willUnload);
} }

View File

@ -34,7 +34,7 @@ export class TransitionController {
return this._ids++; return this._ids++;
} }
get(trnsId: number, enteringView: ViewController, leavingView: ViewController, opts: AnimationOptions) { get(trnsId: number, enteringView: ViewController, leavingView: ViewController, opts: AnimationOptions): Transition {
const trns = createTransition(this._config, opts.animation, enteringView, leavingView, opts); const trns = createTransition(this._config, opts.animation, enteringView, leavingView, opts);
trns.trnsId = trnsId; trns.trnsId = trnsId;

View File

@ -1,4 +1,5 @@
import { Config } from '../config/config'; import { Config } from '../config/config';
import { Transition } from './transition';
import { IOSTransition } from './transition-ios'; import { IOSTransition } from './transition-ios';
import { MDTransition } from './transition-md'; import { MDTransition } from './transition-md';
import { WPTransition } from './transition-wp'; import { WPTransition } from './transition-wp';
@ -62,7 +63,7 @@ export function registerTransitions(config: Config) {
} }
export function createTransition(config: Config, transitionName: string, enteringView: any, leavingView: any, opts: any) { export function createTransition(config: Config, transitionName: string, enteringView: any, leavingView: any, opts: any): Transition {
let TransitionClass: any = config.getTransition(transitionName); let TransitionClass: any = config.getTransition(transitionName);
if (!TransitionClass) { if (!TransitionClass) {
// didn't find a transition animation, default to ios-transition // didn't find a transition animation, default to ios-transition

View File

@ -21,10 +21,8 @@ export class Transition extends Animation {
_trnsStart: Function; _trnsStart: Function;
parent: Transition; parent: Transition;
hasChildTrns: boolean = false;
trnsId: number; trnsId: number;
constructor(public enteringView: ViewController, public leavingView: ViewController, opts: AnimationOptions, raf?: Function) { constructor(public enteringView: ViewController, public leavingView: ViewController, opts: AnimationOptions, raf?: Function) {
super(null, opts, raf); super(null, opts, raf);
} }
@ -35,6 +33,10 @@ export class Transition extends Animation {
this._trnsStart = trnsStart; this._trnsStart = trnsStart;
} }
isRoot(): boolean {
return !this.parent;
}
start() { start() {
this._trnsStart && this._trnsStart(); this._trnsStart && this._trnsStart();
this._trnsStart = null; this._trnsStart = null;

View File

@ -275,9 +275,9 @@ export const mockNavController = function(): NavControllerBase {
enteringView._state = ViewState.INITIALIZED; enteringView._state = ViewState.INITIALIZED;
}; };
(<any>nav)._orgViewInsert = nav._viewInsert; (<any>nav)._orgViewInsert = nav._viewAttachToDOM;
nav._viewInsert = function(view: ViewController, componentRef: ComponentRef<any>, viewport: ViewContainerRef) { nav._viewAttachToDOM = function(view: ViewController, componentRef: ComponentRef<any>, viewport: ViewContainerRef) {
let mockedViewport: any = { let mockedViewport: any = {
insert: () => { } insert: () => { }
}; };