Skip to content

Commit 584afd0

Browse files
committed
fix(navigation): fix null pointer exceptions that would occur when destroying a nav controller while its transitioning
1 parent de0f9d5 commit 584afd0

File tree

2 files changed

+39
-33
lines changed

2 files changed

+39
-33
lines changed

src/navigation/nav-controller-base.ts

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export class NavControllerBase extends Ion implements NavController {
6262
_viewport: ViewContainerRef;
6363
_views: ViewController[] = [];
6464
_zIndexOffset: number = 0;
65+
_destroyed: boolean;
6566

6667
viewDidLoad: EventEmitter<any> = new EventEmitter();
6768
viewWillEnter: EventEmitter<any> = new EventEmitter();
@@ -102,6 +103,7 @@ export class NavControllerBase extends Ion implements NavController {
102103
this._sbEnabled = config.getBoolean('swipeBackEnabled');
103104
this._children = [];
104105
this.id = 'n' + (++ctrlIds);
106+
this._destroyed = false;
105107
}
106108

107109
push(page: any, params?: any, opts?: NavOptions, done?: () => void): Promise<any> {
@@ -284,7 +286,7 @@ export class NavControllerBase extends Ion implements NavController {
284286
if (ti.done) {
285287
ti.done(false, false, rejectReason);
286288
}
287-
if (ti.reject) {
289+
if (ti.reject && !this._destroyed) {
288290
ti.reject(rejectReason);
289291
} else {
290292
ti.resolve(false);
@@ -594,7 +596,6 @@ export class NavControllerBase extends Ion implements NavController {
594596
}
595597

596598
_transition(enteringView: ViewController, leavingView: ViewController, ti: TransitionInstruction): Promise<NavResult> {
597-
598599
if (!ti.requiresTransition) {
599600
// transition is not required, so we are already done!
600601
// they're inserting/removing the views somewhere in the middle or
@@ -856,35 +857,38 @@ export class NavControllerBase extends Ion implements NavController {
856857
_cleanup(activeView: ViewController) {
857858
// ok, cleanup time!! Destroy all of the views that are
858859
// INACTIVE and come after the active view
859-
const activeViewIndex = this._views.indexOf(activeView);
860-
const views = this._views;
861-
let reorderZIndexes = false;
862-
let view: ViewController;
863-
let i: number;
860+
// only do this if the views exist, though
861+
if (!this._destroyed) {
862+
const activeViewIndex = this._views.indexOf(activeView);
863+
const views = this._views;
864+
let reorderZIndexes = false;
865+
let view: ViewController;
866+
let i: number;
864867

865-
for (i = views.length - 1; i >= 0; i--) {
866-
view = views[i];
867-
if (i > activeViewIndex) {
868-
// this view comes after the active view
869-
// let's unload it
870-
this._willUnload(view);
871-
this._destroyView(view);
872-
873-
} else if (i < activeViewIndex && !this._isPortal) {
874-
// this view comes before the active view
875-
// and it is not a portal then ensure it is hidden
876-
view._domShow(false, this._renderer);
877-
}
878-
if (view._zIndex <= 0) {
879-
reorderZIndexes = true;
868+
for (i = views.length - 1; i >= 0; i--) {
869+
view = views[i];
870+
if (i > activeViewIndex) {
871+
// this view comes after the active view
872+
// let's unload it
873+
this._willUnload(view);
874+
this._destroyView(view);
875+
876+
} else if (i < activeViewIndex && !this._isPortal) {
877+
// this view comes before the active view
878+
// and it is not a portal then ensure it is hidden
879+
view._domShow(false, this._renderer);
880+
}
881+
if (view._zIndex <= 0) {
882+
reorderZIndexes = true;
883+
}
880884
}
881-
}
882885

883-
if (!this._isPortal && reorderZIndexes) {
884-
for (i = 0; i < views.length; i++) {
885-
view = views[i];
886-
// ******** DOM WRITE ****************
887-
view._setZIndex(view._zIndex + INIT_ZINDEX + 1, this._renderer);
886+
if (!this._isPortal && reorderZIndexes) {
887+
for (i = 0; i < views.length; i++) {
888+
view = views[i];
889+
// ******** DOM WRITE ****************
890+
view._setZIndex(view._zIndex + INIT_ZINDEX + 1, this._renderer);
891+
}
888892
}
889893
}
890894
}
@@ -1021,6 +1025,8 @@ export class NavControllerBase extends Ion implements NavController {
10211025
if (this.parent && this.parent.unregisterChildNav) {
10221026
this.parent.unregisterChildNav(this);
10231027
}
1028+
1029+
this._destroyed = true;
10241030
}
10251031

10261032
swipeBackStart() {

src/navigation/test/nav-controller.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,13 +1099,13 @@ describe('NavController', () => {
10991099

11001100
it('should not crash when destroyed while transitioning', (done) => {
11011101
let view1 = mockView(MockView1);
1102-
nav.push(view1).then(() => {
1103-
fail('it should not succeed');
1102+
nav.push(view1).then((succeded: boolean) => {
1103+
expect(succeded).toEqual(false);
11041104
done();
1105-
}).catch((err: any) => {
1106-
expect(err).toEqual('nav controller was destroyed');
1105+
}).catch(() => {
1106+
fail('should never get here');
11071107
done();
1108-
});
1108+
});
11091109
nav.destroy();
11101110
}, 10000);
11111111
});

0 commit comments

Comments
 (0)