Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 9b3a3ba

Browse files
Merge pull request #1750 from NativeScript/djenkov/release-to-master
fix(location-strategy): crash on going back with router-outlet after closing modal
2 parents 402fbde + 878f44d commit 9b3a3ba

File tree

9 files changed

+107
-39
lines changed

9 files changed

+107
-39
lines changed

‎e2e/single-page/app/app.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.title {
2-
font-size: 30;
2+
font-size: 15;
33
margin: 16;
44
}
55

‎e2e/single-page/app/app.module.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,19 @@ import { AppComponent } from "./app.component";
1111

1212
import { rendererTraceCategory, viewUtilCategory, routeReuseStrategyTraceCategory, routerTraceCategory } from "nativescript-angular/trace";
1313
import { setCategories, enable } from "tns-core-modules/trace";
14+
import { ModalComponent } from "./second/modal/modal.component";
1415
setCategories(routerTraceCategory + "," + routeReuseStrategyTraceCategory);
1516
enable();
1617

1718
@NgModule({
1819
declarations: [
1920
AppComponent,
21+
ModalComponent,
2022
...navigatableComponents,
2123
],
24+
entryComponents:[
25+
ModalComponent
26+
],
2227
bootstrap: [AppComponent],
2328
providers: [
2429
{ provide: NgModuleFactoryLoader, useClass: NSModuleFactoryLoader }
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<StackLayout>
2+
<Label text="Welcome to modal"></Label>
3+
<Button text="Close Modal" (tap)="close()"></Button>
4+
</StackLayout>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { Component } from '@angular/core';
2+
import { ModalDialogParams } from "nativescript-angular/modal-dialog";
3+
4+
@Component({
5+
moduleId: module.id,
6+
selector: 'modal',
7+
templateUrl: './modal.component.html'
8+
})
9+
10+
export class ModalComponent {
11+
12+
constructor(private params: ModalDialogParams) {
13+
}
14+
15+
public close() {
16+
this.params.closeCallback();
17+
}
18+
19+
}

‎e2e/single-page/app/second/second.component.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
import { Component, OnInit, OnDestroy } from "@angular/core";
1+
import { Component, OnInit, OnDestroy,ViewContainerRef } from "@angular/core";
22
import { ActivatedRoute, Router, Route } from "@angular/router";
33

4+
import { ModalDialogService, ModalDialogOptions } from "nativescript-angular";
45
import { Page } from "tns-core-modules/ui/page";
56
import { Observable } from "rxjs";
67
import { map } from "rxjs/operators";
78
import { RouterExtensions } from "nativescript-angular/router";
9+
import { ModalComponent } from "./modal/modal.component";
810

911
@Component({
1012
selector: "second",
@@ -19,12 +21,16 @@ import { RouterExtensions } from "nativescript-angular/router";
1921
2022
<StackLayout>
2123
<Label [text]="'Second Component: ' + (id$ | async)" class="title"></Label>
24+
<Button text="Show Modal" (tap)="onShowModal()"></Button>
2225
<Button text="Back" (tap)="back()"></Button>
2326
</StackLayout>`
2427
})
2528
export class SecondComponent implements OnInit, OnDestroy {
2629
public id$: Observable<number>;
27-
constructor(route: ActivatedRoute, private routerExtensions: RouterExtensions) {
30+
constructor(route: ActivatedRoute,
31+
private routerExtensions: RouterExtensions,
32+
private viewContainerRef: ViewContainerRef,
33+
private modalService: ModalDialogService) {
2834
this.id$ = route.params.pipe(map(r => +r["id"]));
2935
}
3036

@@ -39,4 +45,16 @@ export class SecondComponent implements OnInit, OnDestroy {
3945
back() {
4046
this.routerExtensions.back();
4147
}
48+
49+
onShowModal() {
50+
let options: ModalDialogOptions = {
51+
viewContainerRef: this.viewContainerRef,
52+
context: {
53+
},
54+
fullscreen: true
55+
};
56+
57+
this.modalService.showModal(ModalComponent, options).then((dialogResult: string) => {
58+
});
59+
}
4260
}

‎e2e/single-page/e2e/tests.e2e-spec.ts

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,29 +19,45 @@ describe("Single page app", () => {
1919
});
2020

2121
it("should load second(1) page", async () => {
22-
await findAndClick(driver, "SECOND(1)")
22+
await findAndClick(driver, "SECOND(1)");
2323

2424
await driver.findElementByAutomationText("Second Component: 1");
25-
25+
2626
// ActionBar Title and item
2727
await driver.findElementByAutomationText("Second Title");
2828
await driver.findElementByAutomationText("ACTION2");
2929
});
3030

3131
it("should load second(2) page", async () => {
32-
await findAndClick(driver, "SECOND(2)")
32+
await findAndClick(driver, "SECOND(2)");
33+
34+
await driver.findElementByAutomationText("Second Component: 2");
3335

34-
await driver.findElementByAutomationText("Second Component: 1");
35-
3636
// ActionBar Title and items
3737
await driver.findElementByAutomationText("Second Title");
3838
await driver.findElementByAutomationText("ACTION2");
3939
await driver.findElementByAutomationText("ADD");
4040
});
41+
42+
it("should open and close modal view", async () => {
43+
await findAndClick(driver, "Show Modal");
44+
45+
await driver.findElementByAutomationText("Welcome to modal");
46+
await findAndClick(driver, "Close Modal");
47+
48+
await driver.findElementByAutomationText("Second Component: 2");
49+
});
50+
51+
it("should go back to second(1) and first", async () => {
52+
await findAndClick(driver, "Back");
53+
await driver.findElementByAutomationText("Second Component: 1");
54+
await findAndClick(driver, "Back");
55+
await driver.findElementByAutomationText("First Title");
56+
await driver.findElementByAutomationText("ACTION1");
57+
});
4158
});
4259

4360
async function findAndClick(driver: AppiumDriver, text: string) {
44-
const navigationButton =
45-
await driver.findElementByAutomationText(text);
46-
navigationButton.click();
61+
const navigationButton = await driver.findElementByAutomationText(text);
62+
await navigationButton.click();
4763
}

‎nativescript-angular/directives/dialogs.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,7 @@ export class ModalDialogService {
8787
frame = (parentView.page && parentView.page.frame) || topmost();
8888
}
8989

90-
if (frame) {
91-
this.location._beginModalNavigation(frame);
92-
}
90+
this.location._beginModalNavigation(frame);
9391

9492
return new Promise((resolve, reject) => {
9593
setTimeout(() => {

‎nativescript-angular/router/ns-location-strategy.ts

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -275,9 +275,13 @@ export class NSLocationStrategy extends LocationStrategy {
275275

276276
if (!outlet) {
277277
const topmostFrame = this.frameService.getFrame();
278-
this.currentOutlet = this.getOutletByFrame(topmostFrame);
278+
this.currentOutlet = this.getOutletByFrame(topmostFrame) || this.currentOutlet;
279+
}
280+
281+
const frameToBack: Frame = this.currentOutlet.getFrameToBack();
282+
if (frameToBack) {
283+
frameToBack.goBack();
279284
}
280-
this.currentOutlet.getFrameToBack().goBack();
281285
} else {
282286
// Nested navigation - just pop the state
283287
if (isLogEnabled()) {
@@ -385,10 +389,11 @@ export class NSLocationStrategy extends LocationStrategy {
385389
routerLog("NSLocationStrategy._beginModalNavigation()");
386390
}
387391

388-
this.currentOutlet = this.getOutletByFrame(frame);
392+
this.currentOutlet = this.getOutletByFrame(frame)||this.currentOutlet;
389393

390394
// It is possible to have frame, but not corresponding Outlet, if
391-
// showing modal dialog on app.component.ts ngOnInit() e.g.
395+
// showing modal dialog on app.component.ts ngOnInit() e.g. In that case
396+
// the modal is treated as none modal navigation.
392397
if (this.currentOutlet) {
393398
this.currentOutlet.showingModal = true;
394399
this._modalNavigationDepth++;
@@ -400,15 +405,18 @@ export class NSLocationStrategy extends LocationStrategy {
400405
routerLog("NSLocationStrategy.closeModalNavigation()");
401406
}
402407

403-
if (this._modalNavigationDepth > 0) {
408+
const isShowingModal = this._modalNavigationDepth > 0;
409+
410+
if (isShowingModal) {
404411
this._modalNavigationDepth--;
405412
}
406413

407414
// currentOutlet should be the one that corresponds to the topmost() frame
408415
const topmostOutlet = this.getOutletByFrame(this.frameService.getFrame());
409-
this.currentOutlet= this.findOutletByModal(this._modalNavigationDepth, true) || topmostOutlet;
416+
constoutlet= this.findOutletByModal(this._modalNavigationDepth, isShowingModal) || topmostOutlet;
410417

411-
if (this.currentOutlet) {
418+
if (outlet) {
419+
this.currentOutlet = outlet;
412420
this.currentOutlet.showingModal = false;
413421
this.callPopState(this.currentOutlet.peekState(), false);
414422
}
@@ -481,7 +489,8 @@ export class NSLocationStrategy extends LocationStrategy {
481489
this.callPopState(null, true, currentOutlet);
482490
}
483491

484-
if (!currentOutlet.isNSEmptyOutlet) {
492+
// Skip frames filtering since currentOutlet is <router-outlet> when no frames available.
493+
if (currentOutlet.frames.length && !currentOutlet.isNSEmptyOutlet) {
485494
currentOutlet.frames = currentOutlet.frames.filter(currentFrame => currentFrame !== frame);
486495
return currentOutlet.frames.length;
487496
}
@@ -554,26 +563,32 @@ export class NSLocationStrategy extends LocationStrategy {
554563
return pathToOutlet || lastPath;
555564
}
556565

557-
findOutletByModal(modalNavigation: number, isShowingModal?: boolean): Outlet {
558-
return this.outlets.find((outlet) => {
559-
let isEqual = outlet.modalNavigationDepth === modalNavigation;
560-
return isShowingModal ? isEqual && outlet.showingModal : isEqual;
561-
});
562-
}
563-
564566
findOutlet(outletKey: string, activatedRouteSnapshot?: ActivatedRouteSnapshot): Outlet {
565-
let outlet: Outlet = this.outlets.find((currentOutlet) => currentOutlet.outletKeys.indexOf(outletKey) > -1);
567+
let outlet: Outlet = this.outlets.find((currentOutlet) => {
568+
let equalModalDepth = currentOutlet.modalNavigationDepth === this._modalNavigationDepth;
569+
return equalModalDepth && currentOutlet.outletKeys.indexOf(outletKey) > -1;
570+
});
566571

567572
// No Outlet with the given outletKey could happen when using nested unnamed p-r-o
568573
// primary -> primary -> prymary
569574
if (!outlet && activatedRouteSnapshot) {
570575
const pathByOutlets = this.getPathByOutlets(activatedRouteSnapshot);
571-
outlet = this.outlets.find((currentOutlet) => currentOutlet.pathByOutlets === pathByOutlets);
576+
outlet = this.outlets.find((currentOutlet) => {
577+
let equalModalDepth = currentOutlet.modalNavigationDepth === this._modalNavigationDepth;
578+
return equalModalDepth && currentOutlet.pathByOutlets === pathByOutlets;
579+
});
572580
}
573581

574582
return outlet;
575583
}
576584

585+
private findOutletByModal(modalNavigation: number, isShowingModal?: boolean): Outlet {
586+
return this.outlets.find((outlet) => {
587+
let equalModalDepth = outlet.modalNavigationDepth === modalNavigation;
588+
return isShowingModal ? equalModalDepth && outlet.showingModal : equalModalDepth;
589+
});
590+
}
591+
577592
private getOutletByFrame(frame: Frame): Outlet {
578593
let outlet;
579594

‎nativescript-angular/router/page-router-outlet.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -422,15 +422,8 @@ export class PageRouterOutlet implements OnDestroy { // tslint:disable-line:dire
422422

423423
private getOutlet(activatedRouteSnapshot: ActivatedRouteSnapshot): Outlet {
424424
const topActivatedRoute = findTopActivatedRouteNodeForOutlet(activatedRouteSnapshot);
425-
const modalNavigation = this.locationStrategy._modalNavigationDepth;
426425
const outletKey = this.locationStrategy.getRouteFullPath(topActivatedRoute);
427-
let outlet;
428-
429-
if (modalNavigation > 0) { // Modal with 'primary' p-r-o
430-
outlet = this.locationStrategy.findOutletByModal(modalNavigation);
431-
} else {
432-
outlet = this.locationStrategy.findOutlet(outletKey, topActivatedRoute);
433-
}
426+
let outlet = this.locationStrategy.findOutlet(outletKey, topActivatedRoute);
434427

435428
// Named lazy loaded outlet.
436429
if (!outlet && this.isEmptyOutlet) {

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /