Skip to content

Commit 4922fc6

Browse files
committed
fix(nav): do not hide pages if an overlay is in the stack
Closes #5430
1 parent 70efe7d commit 4922fc6

File tree

5 files changed

+126
-30
lines changed

5 files changed

+126
-30
lines changed

ionic/components/action-sheet/test/basic/index.ts

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {App, Page, ActionSheet, Modal, NavController, ViewController, Platform} from 'ionic-angular';
1+
import {App, Page, ActionSheet, Alert, Modal, NavController, ViewController, Platform} from 'ionic-angular';
22

33

44
@Page({
@@ -101,6 +101,54 @@ class E2EPage {
101101
this.nav.present(actionSheet);
102102
}
103103

104+
presentActionSheet3(ev) {
105+
this.result = '';
106+
107+
let actionSheet = ActionSheet.create({
108+
buttons: [
109+
{
110+
text: 'Open Alert',
111+
handler: () => {
112+
this.result = 'Opened alert';
113+
114+
let alert = Alert.create();
115+
alert.setTitle('Alert!');
116+
alert.setMessage('Alert opened from an action sheet');
117+
alert.addButton({
118+
text: 'Cancel',
119+
role: 'cancel',
120+
handler: () => {
121+
this.result = 'pressed Cancel button in alert from action sheet';
122+
}
123+
});
124+
alert.addButton({
125+
text: 'Okay',
126+
handler: () => {
127+
this.result = 'pressed Okay button in alert from action sheet';
128+
}
129+
});
130+
131+
this.nav.present(alert).then(() => {
132+
this.result = 'Alert from action sheet opened';
133+
});
134+
135+
// do not close the action sheet yet
136+
return false;
137+
}
138+
},
139+
{
140+
text: 'Cancel',
141+
role: 'cancel',
142+
handler: () => {
143+
this.result = 'Canceled';
144+
}
145+
}
146+
]
147+
});
148+
149+
this.nav.present(actionSheet);
150+
}
151+
104152
}
105153

106154
@Page({

ionic/components/action-sheet/test/basic/main.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<ion-content padding>
77
<button block class="e2eOpenActionSheet" (click)="presentActionSheet1()">Present Action Sheet 1</button>
88
<button block (click)="presentActionSheet2()">Present Action Sheet 2</button>
9+
<button block (click)="presentActionSheet3()">Present Action Sheet 3</button>
910

1011
<pre>
1112
Result: {{result}}

ionic/components/nav/nav-controller.ts

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -984,8 +984,8 @@ export class NavController extends Ion {
984984
// the previous transition was still going when this one started
985985
// so to be safe, only update showing the entering/leaving
986986
// don't hide the others when they could still be transitioning
987-
enteringView.domCache(true, this._renderer);
988-
leavingView.domCache(true, this._renderer);
987+
enteringView.domShow(true, this._renderer);
988+
leavingView.domShow(true, this._renderer);
989989

990990
} else {
991991
// there are no other transitions happening but this one
@@ -1001,7 +1001,7 @@ export class NavController extends Ion {
10011001
(view === leavingView) ||
10021002
view.isOverlay ||
10031003
(i < ii - 1 ? this._views[i + 1].isOverlay : false);
1004-
view.domCache(shouldShow, this._renderer);
1004+
view.domShow(shouldShow, this._renderer);
10051005
}
10061006
}
10071007

@@ -1182,11 +1182,20 @@ export class NavController extends Ion {
11821182

11831183
// make sure only this entering view and PREVIOUS view are the
11841184
// only two views that are not display:none
1185+
// do not make any changes to the stack's current visibility
1186+
// if there is an overlay somewhere in the stack
11851187
leavingView = this.getPrevious(enteringView);
1186-
this._views.forEach(view => {
1187-
let shouldShow = (view === enteringView) || (view === leavingView);
1188-
view.domCache(shouldShow, this._renderer);
1189-
});
1188+
if (this.hasOverlay()) {
1189+
// ensure the entering view is showing
1190+
enteringView.domShow(true, this._renderer);
1191+
1192+
} else {
1193+
// only possibly hide a view if there are no overlays in the stack
1194+
this._views.forEach(view => {
1195+
let shouldShow = (view === enteringView) || (view === leavingView);
1196+
view.domShow(shouldShow, this._renderer);
1197+
});
1198+
}
11901199

11911200
// this check only needs to happen once, which will add the css
11921201
// class to the nav when it's finished its first transition
@@ -1476,6 +1485,19 @@ export class NavController extends Ion {
14761485
this._trnsTime = (isTransitioning ? Date.now() + fallback : 0);
14771486
}
14781487

1488+
/**
1489+
* @private
1490+
* @returns {boolean}
1491+
*/
1492+
hasOverlay(): boolean {
1493+
for (var i = this._views.length - 1; i >= 0; i--) {
1494+
if (this._views[i].isOverlay) {
1495+
return true;
1496+
}
1497+
}
1498+
return false;
1499+
}
1500+
14791501
/**
14801502
* @private
14811503
* @returns {ViewController}

ionic/components/nav/test/nav-controller.spec.ts

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ export function run() {
477477
expect(navOptions.animate).toBe(false);
478478
});
479479

480-
it('should set domCache true when isAlreadyTransitioning', () => {
480+
it('should set domShow true when isAlreadyTransitioning', () => {
481481
let enteringView = new ViewController(Page1);
482482
let leavingView = new ViewController(Page2);
483483
let isAlreadyTransitioning = true;
@@ -486,16 +486,16 @@ export function run() {
486486
nav._beforeTrans = () => {}; //prevent running beforeTrans for tests
487487
nav._renderer = null;
488488

489-
spyOn(enteringView, 'domCache');
490-
spyOn(leavingView, 'domCache');
489+
spyOn(enteringView, 'domShow');
490+
spyOn(leavingView, 'domShow');
491491

492492
nav._postRender(1, enteringView, leavingView, isAlreadyTransitioning, navOptions, done);
493493

494-
expect(enteringView.domCache).toHaveBeenCalledWith(true, nav._renderer);
495-
expect(leavingView.domCache).toHaveBeenCalledWith(true, nav._renderer);
494+
expect(enteringView.domShow).toHaveBeenCalledWith(true, nav._renderer);
495+
expect(leavingView.domShow).toHaveBeenCalledWith(true, nav._renderer);
496496
});
497497

498-
it('should set domCache true when isAlreadyTransitioning false for the entering/leaving views', () => {
498+
it('should set domShow true when isAlreadyTransitioning false for the entering/leaving views', () => {
499499
let view1 = new ViewController(Page1);
500500
let view2 = new ViewController(Page2);
501501
let view3 = new ViewController(Page3);
@@ -506,18 +506,18 @@ export function run() {
506506
nav._renderer = null;
507507
nav._views = [view1, view2, view3];
508508

509-
spyOn(view1, 'domCache');
510-
spyOn(view2, 'domCache');
511-
spyOn(view3, 'domCache');
509+
spyOn(view1, 'domShow');
510+
spyOn(view2, 'domShow');
511+
spyOn(view3, 'domShow');
512512

513513
nav._postRender(1, view3, view2, isAlreadyTransitioning, navOptions, done);
514514

515-
expect(view1.domCache).toHaveBeenCalledWith(false, nav._renderer);
516-
expect(view2.domCache).toHaveBeenCalledWith(true, nav._renderer);
517-
expect(view3.domCache).toHaveBeenCalledWith(true, nav._renderer);
515+
expect(view1.domShow).toHaveBeenCalledWith(false, nav._renderer);
516+
expect(view2.domShow).toHaveBeenCalledWith(true, nav._renderer);
517+
expect(view3.domShow).toHaveBeenCalledWith(true, nav._renderer);
518518
});
519519

520-
it('should set domCache true when isAlreadyTransitioning false for views when a view has isOverlay=true', () => {
520+
it('should set domShow true when isAlreadyTransitioning false for views when a view has isOverlay=true', () => {
521521
let view1 = new ViewController(Page1);
522522
let view2 = new ViewController(Page2);
523523
let view3 = new ViewController(Page3);
@@ -531,17 +531,17 @@ export function run() {
531531

532532
view3.isOverlay = true;
533533

534-
spyOn(view1, 'domCache');
535-
spyOn(view2, 'domCache');
536-
spyOn(view3, 'domCache');
537-
spyOn(view4, 'domCache');
534+
spyOn(view1, 'domShow');
535+
spyOn(view2, 'domShow');
536+
spyOn(view3, 'domShow');
537+
spyOn(view4, 'domShow');
538538

539539
nav._postRender(1, view4, view3, isAlreadyTransitioning, navOptions, done);
540540

541-
expect(view1.domCache).toHaveBeenCalledWith(false, nav._renderer);
542-
expect(view2.domCache).toHaveBeenCalledWith(true, nav._renderer);
543-
expect(view3.domCache).toHaveBeenCalledWith(true, nav._renderer);
544-
expect(view4.domCache).toHaveBeenCalledWith(true, nav._renderer);
541+
expect(view1.domShow).toHaveBeenCalledWith(false, nav._renderer);
542+
expect(view2.domShow).toHaveBeenCalledWith(true, nav._renderer);
543+
expect(view3.domShow).toHaveBeenCalledWith(true, nav._renderer);
544+
expect(view4.domShow).toHaveBeenCalledWith(true, nav._renderer);
545545
});
546546

547547
});
@@ -814,6 +814,31 @@ export function run() {
814814
expect(nav.setTransitioning).not.toHaveBeenCalled();
815815
});
816816

817+
it('should set not run domShow when when any view in the stack has isOverlay=true', () => {
818+
let view1 = new ViewController(Page1);
819+
let view2 = new ViewController(Page2);
820+
let view3 = new ViewController(Page3);
821+
let view4 = new ViewController(Page4);
822+
let hasCompleted = true;
823+
nav._views = [view1, view2, view3, view4];
824+
825+
view1.isOverlay = true;
826+
827+
nav._transIds = 1;
828+
829+
spyOn(view1, 'domShow');
830+
spyOn(view2, 'domShow');
831+
spyOn(view3, 'domShow');
832+
spyOn(view4, 'domShow');
833+
834+
nav._transFinish(1, view4, view3, 'forward', hasCompleted);
835+
836+
expect(view1.domShow).not.toHaveBeenCalled();
837+
expect(view2.domShow).not.toHaveBeenCalled();
838+
expect(view3.domShow).not.toHaveBeenCalled();
839+
expect(view4.domShow).toHaveBeenCalled();
840+
});
841+
817842
});
818843

819844
describe('_insert', () => {

ionic/components/nav/view-controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ export class ViewController {
198198
/**
199199
* @private
200200
*/
201-
domCache(shouldShow: boolean, renderer: Renderer) {
201+
domShow(shouldShow: boolean, renderer: Renderer) {
202202
// using hidden element attribute to display:none and not render views
203203
// renderAttr of '' means the hidden attribute will be added
204204
// renderAttr of null means the hidden attribute will be removed

0 commit comments

Comments
 (0)