diff --git a/e2e/modal-navigation-ng/app/app.component.ts b/e2e/modal-navigation-ng/app/app.component.ts
index b95dd6f01..a86fef745 100644
--- a/e2e/modal-navigation-ng/app/app.component.ts
+++ b/e2e/modal-navigation-ng/app/app.component.ts
@@ -1,8 +1,21 @@
import { Component } from "@angular/core";
+import { Router, NavigationEnd } from "@angular/router";
+import { NSLocationStrategy } from "nativescript-angular/router/ns-location-strategy";
@Component({
selector: "ns-app",
templateUrl: "app.component.html",
})
-export class AppComponent { }
+export class AppComponent {
+ constructor(router: Router, location: NSLocationStrategy) {
+ router.events.subscribe(e => {
+ // console.log("[ROUTER]: " + e.toString());
+
+ if (e instanceof NavigationEnd) {
+ console.log("[ROUTER]: " + e.toString());
+ console.log(location.toString());
+ }
+ });
+ }
+}
diff --git a/e2e/modal-navigation-ng/app/app.module.ts b/e2e/modal-navigation-ng/app/app.module.ts
index 5f3f2e17a..87e0f0857 100644
--- a/e2e/modal-navigation-ng/app/app.module.ts
+++ b/e2e/modal-navigation-ng/app/app.module.ts
@@ -6,6 +6,8 @@ import { AppComponent } from "./app.component";
import { ItemService } from "./item/item.service";
import { ItemsComponent } from "./item/items.component";
import { ItemDetailComponent } from "./item/item-detail.component";
+import { HomeComponent } from "./home/home.component";
+import { ModalTest } from "./modal/modal-test";
// Uncomment and add to NgModule imports if you need to use two-way binding
// import { NativeScriptFormsModule } from "nativescript-angular/forms";
@@ -21,10 +23,14 @@ import { ItemDetailComponent } from "./item/item-detail.component";
NativeScriptModule,
AppRoutingModule
],
+ entryComponents: [...ModalTest.entries],
declarations: [
AppComponent,
ItemsComponent,
- ItemDetailComponent
+ ItemDetailComponent,
+ HomeComponent,
+ ModalTest,
+ ...ModalTest.entries
],
providers: [
ItemService
diff --git a/e2e/modal-navigation-ng/app/app.routing.ts b/e2e/modal-navigation-ng/app/app.routing.ts
index 26c691b5d..b02a5ceb0 100644
--- a/e2e/modal-navigation-ng/app/app.routing.ts
+++ b/e2e/modal-navigation-ng/app/app.routing.ts
@@ -2,13 +2,20 @@ import { NgModule } from "@angular/core";
import { NativeScriptRouterModule } from "nativescript-angular/router";
import { Routes } from "@angular/router";
+import { HomeComponent } from "./home/home.component";
import { ItemsComponent } from "./item/items.component";
import { ItemDetailComponent } from "./item/item-detail.component";
+import { ModalTest } from "./modal/modal-test";
const routes: Routes = [
- { path: "", redirectTo: "/items", pathMatch: "full" },
- { path: "items", component: ItemsComponent },
- { path: "item/:id", component: ItemDetailComponent },
+ { path: "", redirectTo: "/home", pathMatch: "full" },
+
+ { path: "home", component: HomeComponent },
+
+ { path: "modal", component: ModalTest , children: [
+ { path: "items", component: ItemsComponent },
+ { path: "item/:id", component: ItemDetailComponent },
+ ] },
];
@NgModule({
diff --git a/e2e/modal-navigation-ng/app/home/home.component.ts b/e2e/modal-navigation-ng/app/home/home.component.ts
new file mode 100644
index 000000000..8d52b9051
--- /dev/null
+++ b/e2e/modal-navigation-ng/app/home/home.component.ts
@@ -0,0 +1,21 @@
+import { Component, ViewContainerRef } from "@angular/core";
+import { RouterExtensions } from "nativescript-angular/router";
+
+@Component({
+ selector: "modal-test",
+ template: `
+
+
+
+ `
+})
+export class HomeComponent {
+
+ public result: string = "result";
+
+ constructor(private _routerExtensions: RouterExtensions, private vcRef: ViewContainerRef) { }
+
+ public gotToModal() {
+ this._routerExtensions.navigate(["/modal"]); //{clearHistory: true}
+ }
+}
diff --git a/e2e/modal-navigation-ng/app/item/item-detail.component.ts b/e2e/modal-navigation-ng/app/item/item-detail.component.ts
index 9183f7876..0fedf56b0 100644
--- a/e2e/modal-navigation-ng/app/item/item-detail.component.ts
+++ b/e2e/modal-navigation-ng/app/item/item-detail.component.ts
@@ -1,4 +1,4 @@
-import { Component, OnInit } from "@angular/core";
+import { Component, OnInit, OnDestroy } from "@angular/core";
import { ActivatedRoute } from "@angular/router";
import { Item } from "./item";
@@ -9,7 +9,7 @@ import { ItemService } from "./item.service";
moduleId: module.id,
templateUrl: "./item-detail.component.html",
})
-export class ItemDetailComponent implements OnInit {
+export class ItemDetailComponent implements OnInit, OnDestroy {
item: Item;
constructor(
@@ -21,4 +21,7 @@ export class ItemDetailComponent implements OnInit {
const id = +this.route.snapshot.params["id"];
this.item = this.itemService.getItem(id);
}
+
+ ngOnDestroy(): void {
+ }
}
diff --git a/e2e/modal-navigation-ng/app/item/items.component.html b/e2e/modal-navigation-ng/app/item/items.component.html
index 55e87e3ab..6ae2a4ae8 100644
--- a/e2e/modal-navigation-ng/app/item/items.component.html
+++ b/e2e/modal-navigation-ng/app/item/items.component.html
@@ -26,7 +26,7 @@
-
diff --git a/e2e/modal-navigation-ng/app/modal/modal-content.ts b/e2e/modal-navigation-ng/app/modal/modal-content.ts
new file mode 100644
index 000000000..249227ac4
--- /dev/null
+++ b/e2e/modal-navigation-ng/app/modal/modal-content.ts
@@ -0,0 +1,50 @@
+import { Component, Input } from "@angular/core";
+import { ModalDialogParams } from "nativescript-angular/directives/dialogs";
+import { RouterExtensions, PageRoute } from "nativescript-angular/router";
+import { ActivatedRoute } from "@angular/router";
+import { View } from "ui/core/view"
+
+@Component({
+ selector: "modal-content",
+ template: `
+
+
+
+
+
+
+
+
+
+
+ `
+})
+export class ModalContent {
+
+ @Input() public prompt: string;
+ public yes: boolean = true;
+
+ constructor(private params: ModalDialogParams, private nav: RouterExtensions, private activeRoute: ActivatedRoute) {
+ console.log("ModalContent.constructor: " + JSON.stringify(params));
+ this.prompt = params.context.promptMsg;
+ }
+
+ public back() {
+ this.nav.back();
+ }
+
+ public close(layoutRoot: View) {
+ layoutRoot.closeModal();
+ // this.params.closeCallback(res);
+ }
+
+ ngOnInit() {
+ this.nav.navigate(["items"], { relativeTo: this.activeRoute });
+ console.log("ModalContent.ngOnInit");
+ }
+
+ ngOnDestroy() {
+ console.log("ModalContent.ngOnDestroy");
+ }
+
+}
diff --git a/e2e/modal-navigation-ng/app/modal/modal-nested-test.ts b/e2e/modal-navigation-ng/app/modal/modal-nested-test.ts
new file mode 100644
index 000000000..d1ae043f2
--- /dev/null
+++ b/e2e/modal-navigation-ng/app/modal/modal-nested-test.ts
@@ -0,0 +1,23 @@
+import { Component, ViewContainerRef } from "@angular/core";
+import * as dialogs from "ui/dialogs";
+import { ModalDialogService, ModalDialogOptions } from "nativescript-angular/directives/dialogs";
+import { ModalContent } from "./modal-content";
+import { ModalTest } from "./modal-test";
+
+@Component({
+ selector: "modal-nested-test",
+ template: `
+
+ `
+})
+export class ModalNestedTest {
+
+ static entries = [
+ ModalContent
+ ];
+
+ static exports = [
+ ModalTest
+ ];
+
+}
\ No newline at end of file
diff --git a/e2e/modal-navigation-ng/app/modal/modal-test.ts b/e2e/modal-navigation-ng/app/modal/modal-test.ts
new file mode 100644
index 000000000..9e7de20db
--- /dev/null
+++ b/e2e/modal-navigation-ng/app/modal/modal-test.ts
@@ -0,0 +1,109 @@
+import { Component, ViewContainerRef } from "@angular/core";
+import * as dialogs from "ui/dialogs";
+import { ModalDialogService, ModalDialogOptions } from "nativescript-angular/directives/dialogs";
+import { ModalContent } from "./modal-content";
+
+@Component({
+ selector: "modal-test",
+ template: `
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `
+})
+export class ModalTest {
+
+ public result: string = "result";
+
+ constructor(private modal: ModalDialogService, private vcRef: ViewContainerRef) { }
+
+ static entries = [
+ ModalContent
+ ];
+
+ public showModal(fullscreen: boolean) {
+ const options: ModalDialogOptions = {
+ context: { promptMsg: "This is the prompt message!" },
+ fullscreen: fullscreen,
+ viewContainerRef: this.vcRef
+ };
+
+ this.modal.showModal(ModalContent, options).then((res: string) => {
+ this.result = res || "empty result";
+ // console.log("MODAL:" + this.result);
+ });
+ }
+
+ public showAlert() {
+ dialogs.alert({
+ title: "Alert Title",
+ message: "The name will change.",
+ okButtonText: "OK"
+ }).then(() => {
+ this.result = "alert closed";
+ });
+ }
+
+ public showConfirm() {
+ dialogs.confirm({
+ title: "Name",
+ message: "Do you want to change the name?",
+ cancelButtonText: "No",
+ neutralButtonText: "Ignore",
+ okButtonText: "Yes"
+ }).then((confirmResult) => {
+ this.result = confirmResult + "";
+ });
+ }
+
+ public showPrompt() {
+ dialogs.prompt({
+ title: "Name",
+ message: "Enter name:",
+ cancelButtonText: "Cancel",
+ neutralButtonText: "Ignore",
+ okButtonText: "OK",
+ defaultText: "John Reese",
+ inputType: dialogs.inputType.text
+ }).then((promptResult) => {
+ this.result = promptResult.result ? promptResult.text : "no result";
+ });
+ }
+
+ public showAction() {
+ dialogs.action({
+ message: "Choose action:",
+ cancelButtonText: "Close",
+ actions: ["Foo", "Bar"]
+ }).then((actionResult) => {
+ this.result = actionResult;
+ });
+ }
+
+ public showLogin() {
+ dialogs.login({
+ title: "Name",
+ message: "Enter name:",
+ cancelButtonText: "Cancel",
+ neutralButtonText: "Ignore",
+ okButtonText: "OK",
+ userName: "John",
+ password: "Reese"
+ }).then((loginResult) => {
+ this.result = loginResult.result ?
+ ("user: " + loginResult.userName + " pass: " + loginResult.password) :
+ "no result";
+ });
+ }
+
+}
diff --git a/e2e/modal-navigation-ng/e2e/config/appium.capabilities.json b/e2e/modal-navigation-ng/e2e/config/appium.capabilities.json
deleted file mode 100644
index 64f28061b..000000000
--- a/e2e/modal-navigation-ng/e2e/config/appium.capabilities.json
+++ /dev/null
@@ -1,98 +0,0 @@
-{
- "android19": {
- "platformName": "Android",
- "platformVersion": "4.4",
- "deviceName": "Emulator-Api19-Default",
- "avd": "Emulator-Api19-Default",
- "lt": 60000,
- "appActivity": "com.tns.NativeScriptActivity",
- "newCommandTimeout": 720,
- "noReset": true,
- "fullReset": false,
- "app": ""
- },
- "android21": {
- "platformName": "Android",
- "platformVersion": "5.0",
- "deviceName": "Emulator-Api21-Default",
- "avd": "Emulator-Api21-Default",
- "lt": 60000,
- "appActivity": "com.tns.NativeScriptActivity",
- "newCommandTimeout": 720,
- "noReset": true,
- "fullReset": false,
- "app": ""
- },
- "android23": {
- "platformName": "Android",
- "platformVersion": "6.0",
- "deviceName": "Emulator-Api23-Default",
- "avd": "Emulator-Api23-Default",
- "lt": 60000,
- "appActivity": "com.tns.NativeScriptActivity",
- "newCommandTimeout": 720,
- "noReset": true,
- "fullReset": false,
- "app": ""
- },
- "android24": {
- "platformName": "Android",
- "platformVersion": "7.0",
- "deviceName": "Emulator-Api24-Default",
- "avd": "Emulator-Api24-Default",
- "lt": 60000,
- "appActivity": "com.tns.NativeScriptActivity",
- "newCommandTimeout": 720,
- "noReset": true,
- "fullReset": false,
- "app": ""
- },
- "android25": {
- "platformName": "Android",
- "platformVersion": "7.1",
- "deviceName": "Emulator-Api25-Google",
- "avd": "Emulator-Api25-Google",
- "lt": 60000,
- "appActivity": "com.tns.NativeScriptActivity",
- "newCommandTimeout": 720,
- "noReset": true,
- "fullReset": false,
- "app": ""
- },
- "android26": {
- "platformName": "Android",
- "platformVersion": "8.0",
- "deviceName": "Emulator-Api26-Google",
- "avd": "Emulator-Api26-Google",
- "lt": 60000,
- "appActivity": "com.tns.NativeScriptActivity",
- "newCommandTimeout": 720,
- "noReset": true,
- "fullReset": false,
- "app": ""
- },
- "sim.iPhone7.iOS100": {
- "platformName": "iOS",
- "platformVersion": "10.0",
- "deviceName": "iPhone 7 100",
- "noReset": true,
- "fullReset": false,
- "app": ""
- },
- "sim.iPhone8.iOS110": {
- "platformName": "iOS",
- "platformVersion": "11.0",
- "deviceName": "iPhone 8 110",
- "noReset": true,
- "fullReset": false,
- "app": ""
- },
- "sim.iPhoneX.iOS110": {
- "platformName": "iOS",
- "platformVersion": "11.0",
- "deviceName": "iPhone X",
- "noReset": true,
- "fullReset": false,
- "app": ""
- }
-}
diff --git a/e2e/modal-navigation-ng/e2e/config/mocha.opts b/e2e/modal-navigation-ng/e2e/config/mocha.opts
deleted file mode 100644
index 796ec4724..000000000
--- a/e2e/modal-navigation-ng/e2e/config/mocha.opts
+++ /dev/null
@@ -1,4 +0,0 @@
---timeout 80000
---recursive e2e
---reporter mocha-multi
---reporter-options spec=-,mocha-junit-reporter=test-results.xml
\ No newline at end of file
diff --git a/e2e/router-tab-view/app/app.component.html b/e2e/router-tab-view/app/app.component.html
index e148fd408..8872891ae 100644
--- a/e2e/router-tab-view/app/app.component.html
+++ b/e2e/router-tab-view/app/app.component.html
@@ -1,13 +1,11 @@
+ name="playerTab">
+ name="teamTab">
\ No newline at end of file
diff --git a/e2e/router-tab-view/app/app.component.ts b/e2e/router-tab-view/app/app.component.ts
index e0b5f980e..d3e62efe5 100644
--- a/e2e/router-tab-view/app/app.component.ts
+++ b/e2e/router-tab-view/app/app.component.ts
@@ -16,23 +16,11 @@ export class AppComponent {
constructor(router: Router, location: NSLocationStrategy) {
router.events.subscribe(e => {
- // console.log("[ROUTER]: " + e.toString());
-
if (e instanceof NavigationEnd) {
this.isInitialNavigation = false;
console.log("[ROUTER]: " + e.toString());
- // console.log("[ROUTER] NAVIGATION END. Location history:");
- location._getStates().forEach(state => {
- console.log(`[page: ${state.isPageNavigation}] ${state.url}`);
- });
+ console.log(location.toString());
}
})
}
-
- onActivate(tabIndex: number) {
- // if (!this.isInitialNavigation && this.tabView.selectedIndex !== tabIndex) {
- // console.log(`---> onActivate changing tabIndex from: ${this.tabView.selectedIndex} to: ${tabIndex}`);
- // this.tabView.selectedIndex = tabIndex;
- // }
- }
}
diff --git a/e2e/router-tab-view/e2e/config/appium.capabilities.json b/e2e/router-tab-view/e2e/config/appium.capabilities.json
deleted file mode 100644
index 080553981..000000000
--- a/e2e/router-tab-view/e2e/config/appium.capabilities.json
+++ /dev/null
@@ -1,106 +0,0 @@
-{
- "android19": {
- "platformName": "Android",
- "platformVersion": "4.4",
- "deviceName": "Emulator-Api19-Default",
- "avd": "Emulator-Api19-Default",
- "lt": 60000,
- "appActivity": "com.tns.NativeScriptActivity",
- "newCommandTimeout": 720,
- "noReset": true,
- "fullReset": false,
- "app": ""
- },
- "android21": {
- "platformName": "Android",
- "platformVersion": "5.0",
- "deviceName": "Emulator-Api21-Default",
- "avd": "Emulator-Api21-Default",
- "lt": 60000,
- "appActivity": "com.tns.NativeScriptActivity",
- "newCommandTimeout": 720,
- "noReset": true,
- "fullReset": false,
- "app": ""
- },
- "android23": {
- "platformName": "Android",
- "platformVersion": "6.0",
- "deviceName": "Emulator-Api23-Default",
- "avd": "Emulator-Api23-Default",
- "lt": 60000,
- "appActivity": "com.tns.NativeScriptActivity",
- "newCommandTimeout": 720,
- "noReset": true,
- "fullReset": false,
- "app": ""
- },
- "android24": {
- "platformName": "Android",
- "platformVersion": "7.0",
- "deviceName": "Emulator-Api24-Default",
- "avd": "Emulator-Api24-Default",
- "lt": 60000,
- "appActivity": "com.tns.NativeScriptActivity",
- "newCommandTimeout": 720,
- "noReset": true,
- "fullReset": false,
- "app": ""
- },
- "android25": {
- "platformName": "Android",
- "platformVersion": "7.1",
- "deviceName": "Emulator-Api25-Google",
- "avd": "Emulator-Api25-Google",
- "lt": 60000,
- "appActivity": "com.tns.NativeScriptActivity",
- "newCommandTimeout": 720,
- "noReset": true,
- "fullReset": false,
- "app": ""
- },
- "android26": {
- "platformName": "Android",
- "platformVersion": "8.0",
- "deviceName": "Emulator-Api26-Google",
- "avd": "Emulator-Api26-Google",
- "lt": 60000,
- "appActivity": "com.tns.NativeScriptActivity",
- "newCommandTimeout": 720,
- "noReset": true,
- "fullReset": false,
- "app": ""
- },
- "sim.iPhone7.iOS100": {
- "platformName": "iOS",
- "platformVersion": "10.0",
- "deviceName": "iPhone 7 100",
- "noReset": true,
- "fullReset": false,
- "app": ""
- },
- "sim.iPhone7.iOS112": {
- "platformName": "iOS",
- "platformVersion": "11.2",
- "deviceName": "iPhone 7",
- "noReset": true,
- "fullReset": false,
- "app": ""
- },
- "sim.iPhone8.iOS110": {
- "platformName": "iOS",
- "platformVersion": "11.0",
- "deviceName": "iPhone 8 110",
- "noReset": true,
- "fullReset": false,
- "app": ""
- },
- "sim.iPhoneX.iOS110": {
- "platformName": "iOS",
- "platformVersion": "11.0",
- "deviceName": "iPhone X",
- "noReset": true,
- "fullReset": false,
- "app": ""
- }
-}
diff --git a/e2e/router-tab-view/e2e/config/mocha.opts b/e2e/router-tab-view/e2e/config/mocha.opts
deleted file mode 100644
index 796ec4724..000000000
--- a/e2e/router-tab-view/e2e/config/mocha.opts
+++ /dev/null
@@ -1,4 +0,0 @@
---timeout 80000
---recursive e2e
---reporter mocha-multi
---reporter-options spec=-,mocha-junit-reporter=test-results.xml
\ No newline at end of file
diff --git a/e2e/router-tab-view/e2e/tab-view-navigation.e2e-spec.ts b/e2e/router-tab-view/e2e/tab-view-navigation.e2e-spec.ts
index 3bafee864..d169ff7e3 100644
--- a/e2e/router-tab-view/e2e/tab-view-navigation.e2e-spec.ts
+++ b/e2e/router-tab-view/e2e/tab-view-navigation.e2e-spec.ts
@@ -19,7 +19,7 @@ describe("TabView with page-router-outlet in each tab", () => {
}
});
- it("should find an tabs by text", async () => {
+ it("should find any tabs by text", async () => {
await driver.findElementByText("Players", SearchOptions.exact);
await driver.findElementByText("Teams", SearchOptions.exact);
await driver.findElementByText("Player List", SearchOptions.exact);
diff --git a/e2e/single-page/app/second/second.component.ts b/e2e/single-page/app/second/second.component.ts
index 516cc2642..1cfa15616 100644
--- a/e2e/single-page/app/second/second.component.ts
+++ b/e2e/single-page/app/second/second.component.ts
@@ -4,6 +4,7 @@ import { ActivatedRoute, Router, Route } from "@angular/router";
import { Page } from "ui/page";
import { Observable } from "rxjs";
import { map } from "rxjs/operators";
+import { RouterExtensions } from "nativescript-angular/router";
@Component({
selector: "second",
@@ -18,11 +19,12 @@ import { map } from "rxjs/operators";
+
`
})
export class SecondComponent implements OnInit, OnDestroy {
public id$: Observable;
- constructor(route: ActivatedRoute) {
+ constructor(route: ActivatedRoute, private routerExtensions: RouterExtensions) {
this.id$ = route.params.pipe(map(r => +r["id"]));
}
@@ -33,4 +35,8 @@ export class SecondComponent implements OnInit, OnDestroy {
ngOnDestroy() {
console.log("SecondComponent - ngOnDestroy()");
}
+
+ back() {
+ this.routerExtensions.back();
+ }
}
\ No newline at end of file
diff --git a/nativescript-angular/app-host-view.ts b/nativescript-angular/app-host-view.ts
index 021567e3a..60c0fca72 100644
--- a/nativescript-angular/app-host-view.ts
+++ b/nativescript-angular/app-host-view.ts
@@ -1,6 +1,43 @@
import { ContentView } from "tns-core-modules/ui/content-view";
-import { ViewBase } from "tns-core-modules/ui/core/view/view";
+import { GridLayout } from "tns-core-modules/ui/layouts/grid-layout";
+import { ProxyViewContainer } from "tns-core-modules/ui/proxy-view-container";
+import { View } from "tns-core-modules/ui/core/view";
export class AppHostView extends ContentView {
- ngAppRoot: ViewBase;
+
+ private _ngAppRoot: View;
+ private _content: View;
+
+ get ngAppRoot(): View {
+ return this._ngAppRoot;
+ }
+
+ set ngAppRoot(value: View) {
+ this._ngAppRoot = value;
+ }
+
+ get content(): View {
+ return this._content;
+ }
+
+ set content(value: View) {
+ if (this._content) {
+ this._content.parentNode = undefined;
+ }
+
+ this._content = value;
+
+ if (value) {
+ this._content.parentNode = this;
+ }
+
+ this.ngAppRoot = value;
+
+ if (this._content instanceof ProxyViewContainer) {
+ const grid = new GridLayout();
+ grid.addChild(this._content);
+ this.ngAppRoot = grid;
+ }
+ }
+
}
diff --git a/nativescript-angular/directives/dialogs.ts b/nativescript-angular/directives/dialogs.ts
index 8907f44cb..fcbe436f6 100644
--- a/nativescript-angular/directives/dialogs.ts
+++ b/nativescript-angular/directives/dialogs.ts
@@ -9,8 +9,9 @@ import {
ViewContainerRef,
} from "@angular/core";
-import { Page } from "tns-core-modules/ui/page";
+import { NSLocationStrategy } from "../router/ns-location-strategy";
import { View, ViewBase } from "tns-core-modules/ui/core/view";
+import { ProxyViewContainer } from "tns-core-modules/ui/proxy-view-container/proxy-view-container";
import { AppHostView } from "../app-host-view";
import { DetachedLoader } from "../common/detached-loader";
@@ -43,6 +44,9 @@ interface ShowDialogOptions {
@Injectable()
export class ModalDialogService {
+ constructor(private location: NSLocationStrategy) {
+ }
+
public showModal(type: Type,
{ viewContainerRef, moduleRef, context, fullscreen }: ModalDialogOptions
): Promise {
@@ -65,8 +69,10 @@ export class ModalDialogService {
const componentContainer = moduleRef || viewContainerRef;
const resolver = componentContainer.injector.get(ComponentFactoryResolver);
+ this.location._beginModalNavigation();
+
return new Promise(resolve => {
- setTimeout(() => ModalDialogService.showDialog({
+ setTimeout(() => this._showDialog({
containerRef: viewContainerRef,
context,
doneCallback: resolve,
@@ -79,7 +85,7 @@ export class ModalDialogService {
});
}
- private static showDialog({
+ private _showDialog({
containerRef,
context,
doneCallback,
@@ -89,41 +95,48 @@ export class ModalDialogService {
resolver,
type,
}: ShowDialogOptions): void {
- const page = pageFactory({ isModal: true, componentType: type });
-
+ let componentView: View;
let detachedLoaderRef: ComponentRef;
+
const closeCallback = (...args) => {
doneCallback.apply(undefined, args);
- page.closeModal();
- detachedLoaderRef.instance.detectChanges();
- detachedLoaderRef.destroy();
+ if (componentView && !this.location._isModalClosing) {
+ this.location._beginCloseModalNavigation();
+
+ componentView.closeModal();
+ } else if (this.location._isModalClosing) {
+ this.location.back();
+ this.location._finishCloseModalNavigation();
+ detachedLoaderRef.instance.detectChanges();
+ detachedLoaderRef.destroy();
+ }
};
const modalParams = new ModalDialogParams(context, closeCallback);
-
const providers = ReflectiveInjector.resolve([
- { provide: Page, useValue: page },
{ provide: ModalDialogParams, useValue: modalParams },
]);
- const childInjector = ReflectiveInjector.fromResolvedProviders(
- providers, containerRef.parentInjector);
+ const childInjector = ReflectiveInjector.fromResolvedProviders(providers, containerRef.parentInjector);
const detachedFactory = resolver.resolveComponentFactory(DetachedLoader);
detachedLoaderRef = containerRef.createComponent(detachedFactory, -1, childInjector, null);
detachedLoaderRef.instance.loadComponent(type).then((compRef) => {
- const componentView = compRef.location.nativeElement;
+ const detachedProxy = compRef.location.nativeElement;
+
+ if (detachedProxy.getChildrenCount() > 1) {
+ throw new Error("Modal content has more than one root view.");
+ }
+ componentView = detachedProxy.getChildAt(0);
if (componentView.parent) {
(componentView.parent).removeChild(componentView);
}
- page.content = componentView;
- parentView.showModal(page, context, closeCallback, fullscreen);
+ parentView.showModal(componentView, context, closeCallback, fullscreen);
});
}
}
-
@Directive({
selector: "[modal-dialog-host]" // tslint:disable-line:directive-selector
})
diff --git a/nativescript-angular/platform-common.ts b/nativescript-angular/platform-common.ts
index b37262098..91ce4df2d 100644
--- a/nativescript-angular/platform-common.ts
+++ b/nativescript-angular/platform-common.ts
@@ -172,7 +172,7 @@ export class NativeScriptPlatformRef extends PlatformRef {
bootstrapLog(`Angular bootstrap bootstrap done. uptime: ${uptime()}`);
if (!autoCreateFrame) {
- rootContent = this.extractContentFromHost(tempAppHostView);
+ rootContent = tempAppHostView.content;
}
lastBootstrappedModule = new WeakRef(moduleRef);
@@ -233,7 +233,7 @@ export class NativeScriptPlatformRef extends PlatformRef {
onAfterLivesync.next({ moduleRef });
if (!autoCreateFrame) {
- rootContent = this.extractContentFromHost(tempAppHostView);
+ rootContent = tempAppHostView.content;
}
lastBootstrappedModule = new WeakRef(moduleRef);
@@ -282,12 +282,4 @@ export class NativeScriptPlatformRef extends PlatformRef {
frame.navigate({ create: () => { return page; } });
return { page, frame };
}
-
- private extractContentFromHost(tempAppHostView: AppHostView) {
- const result = tempAppHostView.content;
- tempAppHostView.content = null;
- tempAppHostView.ngAppRoot = result;
- result.parentNode = tempAppHostView;
- return result;
- }
}
diff --git a/nativescript-angular/router/ns-location-strategy.ts b/nativescript-angular/router/ns-location-strategy.ts
index ca26635e8..c220d9084 100644
--- a/nativescript-angular/router/ns-location-strategy.ts
+++ b/nativescript-angular/router/ns-location-strategy.ts
@@ -1,5 +1,6 @@
import { Injectable } from "@angular/core";
import { LocationStrategy } from "@angular/common";
+import { DefaultUrlSerializer, UrlSegmentGroup, UrlTree } from "@angular/router";
import { routerLog } from "../trace";
import { NavigationTransition } from "tns-core-modules/ui/frame";
import { isPresent } from "../lang-facade";
@@ -19,29 +20,51 @@ const defaultNavOptions: NavigationOptions = {
export interface LocationState {
state: any;
title: string;
- url: string;
queryParams: string;
+ segmentGroup: UrlSegmentGroup;
+ isRootSegmentGroup: boolean;
isPageNavigation: boolean;
+ isModalNavigation: boolean;
}
@Injectable()
export class NSLocationStrategy extends LocationStrategy {
- private states = new Array();
+ private statesByOutlet: { [key: string]: Array } = {};
+ private currentUrlTree: UrlTree;
+ private currentOutlet: string;
private popStateCallbacks = new Array<(_: any) => any>();
private _isPageNavigationBack = false;
private _currentNavigationOptions: NavigationOptions;
+ public _isModalClosing = false;
+ public _isModalNavigation = false;
+
constructor(private frameService: FrameService) {
super();
routerLog("NSLocationStrategy.constructor()");
}
path(): string {
- let state = this.peekState();
- const result = state ? state.url : "/";
- routerLog("NSLocationStrategy.path(): " + result);
- return result;
+ if (!this.currentUrlTree) {
+ return "/";
+ }
+
+ let tree = this.currentUrlTree;
+ const state = this.peekState(this.currentOutlet);
+
+ // Handle case where the user declares a component at path "/".
+ // The url serializer doesn't parse this url as having a primary outlet.
+ if (state.isRootSegmentGroup) {
+ tree.root = state.segmentGroup;
+ } else {
+ tree.root.children[this.currentOutlet] = state.segmentGroup;
+ }
+
+ const urlSerializer = new DefaultUrlSerializer();
+ const url = urlSerializer.serialize(tree);
+ routerLog("NSLocationStrategy.path(): " + url);
+ return url;
}
prepareExternalUrl(internal: string): string {
@@ -50,31 +73,77 @@ export class NSLocationStrategy extends LocationStrategy {
}
pushState(state: any, title: string, url: string, queryParams: string): void {
- routerLog("NSLocationStrategy.pushState state: " +
+ routerLog("NSLocationStrategy.pushState state: " +
`${state}, title: ${title}, url: ${url}, queryParams: ${queryParams}`);
this.pushStateInternal(state, title, url, queryParams);
}
pushStateInternal(state: any, title: string, url: string, queryParams: string): void {
- let isNewPage = this.states.length === 0;
- this.states.push({
- state: state,
- title: title,
- url: url,
- queryParams: queryParams,
- isPageNavigation: isNewPage
+ const urlSerializer = new DefaultUrlSerializer();
+ const stateUrlTree: UrlTree = urlSerializer.parse(url);
+ const rootOutlets = stateUrlTree.root.children;
+
+ this.currentUrlTree = stateUrlTree;
+
+ // Handle case where the user declares a component at path "/".
+ // The url serializer doesn't parse this url as having a primary outlet.
+ if (!Object.keys(rootOutlets).length) {
+ const outletStates = this.statesByOutlet["primary"] = this.statesByOutlet["primary"] || [];
+ const isNewPage = outletStates.length === 0;
+ outletStates.push({
+ state: state,
+ title: title,
+ queryParams: queryParams,
+ segmentGroup: stateUrlTree.root,
+ isRootSegmentGroup: true,
+ isPageNavigation: isNewPage,
+ isModalNavigation: false
+ });
+ this.currentOutlet = "primary";
+ }
+
+ Object.keys(rootOutlets).forEach(outletName => {
+ const outletStates = this.statesByOutlet[outletName] = this.statesByOutlet[outletName] || [];
+ const isNewPage = outletStates.length === 0;
+ const lastState = this.peekState(outletName);
+
+ if (!lastState || lastState.segmentGroup.toString() !== rootOutlets[outletName].toString()) {
+ outletStates.push({
+ state: state,
+ title: title,
+ queryParams: queryParams,
+ segmentGroup: rootOutlets[outletName],
+ isRootSegmentGroup: false,
+ isPageNavigation: isNewPage,
+ isModalNavigation: false
+ });
+
+ this.currentOutlet = outletName;
+ }
});
}
replaceState(state: any, title: string, url: string, queryParams: string): void {
- if (this.states.length > 0) {
+ const states = this.statesByOutlet[this.currentOutlet];
+ if (states && states.length > 0) {
routerLog("NSLocationStrategy.replaceState changing existing state: " +
`${state}, title: ${title}, url: ${url}, queryParams: ${queryParams}`);
- const topState = this.peekState();
- topState.state = state;
- topState.title = title;
- topState.url = url;
- topState.queryParams = queryParams;
+
+ const tree = this.currentUrlTree;
+ if (url !== tree.toString()) {
+ const urlSerializer = new DefaultUrlSerializer();
+ const stateUrlTree: UrlTree = urlSerializer.parse(url);
+ const rootOutlets = stateUrlTree.root.children;
+
+ Object.keys(rootOutlets).forEach(outletName => {
+ const topState = this.peekState(outletName);
+
+ topState.segmentGroup = rootOutlets[outletName];
+ topState.state = state;
+ topState.title = title;
+ topState.queryParams = queryParams;
+ });
+ }
} else {
routerLog("NSLocationStrategy.replaceState pushing new state: " +
`${state}, title: ${title}, url: ${url}, queryParams: ${queryParams}`);
@@ -87,21 +156,52 @@ export class NSLocationStrategy extends LocationStrategy {
}
back(): void {
- if (this._isPageNavigationBack) {
+ if (this._isModalClosing) {
+ const states = this.statesByOutlet[this.currentOutlet];
+ // We are closing modal view
+ // clear the stack until we get to the page that opened the modal view
+ let state;
+ let modalStatesCleared = false;
+ let count = 1;
+
+ while (!modalStatesCleared) {
+ state = this.peekState(this.currentOutlet);
+
+ if (!state) {
+ modalStatesCleared = true;
+ continue;
+ }
+
+ if (!state.isModalNavigation) {
+ states.pop();
+ count++;
+ } else {
+ modalStatesCleared = true;
+ state.isModalNavigation = false;
+ }
+ }
+
+ routerLog("NSLocationStrategy.back() while closing modal. States popped: " + count);
+
+ if (state) {
+ this.callPopState(state, true);
+ }
+ } else if (this._isPageNavigationBack) {
+ const states = this.statesByOutlet[this.currentOutlet];
// We are navigating to the previous page
// clear the stack until we get to a page navigation state
- let state = this.states.pop();
+ let state = states.pop();
let count = 1;
- while (!(state.isPageNavigation)) {
- state = this.states.pop();
+ while (!state.isPageNavigation) {
+ state = states.pop();
count++;
}
routerLog("NSLocationStrategy.back() while navigating back. States popped: " + count);
this.callPopState(state, true);
} else {
- let state = this.peekState();
+ let state = this.peekState(this.currentOutlet);
if (state.isPageNavigation) {
// This was a page navigation - so navigate through frame.
routerLog("NSLocationStrategy.back() while not navigating back but top" +
@@ -112,14 +212,15 @@ export class NSLocationStrategy extends LocationStrategy {
// Nested navigation - just pop the state
routerLog("NSLocationStrategy.back() while not navigating back but top" +
" state is not page - just pop");
- this.callPopState(this.states.pop(), true);
+
+ this.callPopState(this.statesByOutlet[this.currentOutlet].pop(), true);
}
}
}
canGoBack() {
- return this.states.length > 1;
+ return this.statesByOutlet[this.currentOutlet].length > 1;
}
onPopState(fn: (_: any) => any): void {
@@ -133,33 +234,48 @@ export class NSLocationStrategy extends LocationStrategy {
}
private callPopState(state: LocationState, pop: boolean = true) {
- const change = { url: state.url, pop: pop };
+ const urlSerializer = new DefaultUrlSerializer();
+ this.currentUrlTree.root.children[this.currentOutlet] = state.segmentGroup;
+ const url = urlSerializer.serialize(this.currentUrlTree);
+ const change = { url: url, pop: pop };
for (let fn of this.popStateCallbacks) {
fn(change);
}
}
- private peekState(): LocationState {
- if (this.states.length > 0) {
- return this.states[this.states.length - 1];
+ private peekState(name: string) {
+ const states = this.statesByOutlet[name] || [];
+ if (states.length > 0) {
+ return states[states.length - 1];
}
return null;
}
public toString() {
- return this.states
- .map((v, i) => `${i}.[${v.isPageNavigation ? "PAGE" : "INTERNAL"}] "${v.url}"`)
- .reverse()
- .join("\n");
+ let result = [];
+
+ Object.keys(this.statesByOutlet).forEach(outletName => {
+ const outletStates = this.statesByOutlet[outletName];
+ const outletLog = outletStates
+ // tslint:disable-next-line:max-line-length
+ .map((v, i) => `${outletName}.${i}.[${v.isPageNavigation ? "PAGE" : "INTERNAL"}].[${v.isModalNavigation ? "MODAL" : "BASE"}] "${v.segmentGroup.toString()}"`)
+ .reverse();
+
+
+ result = result.concat(outletLog);
+ });
+
+ return result.join("\n");
}
// Methods for syncing with page navigation in PageRouterOutlet
- public _beginBackPageNavigation() {
+ public _beginBackPageNavigation(name: string) {
routerLog("NSLocationStrategy.startGoBack()");
if (this._isPageNavigationBack) {
throw new Error("Calling startGoBack while going back.");
}
this._isPageNavigationBack = true;
+ this.currentOutlet = name;
}
public _finishBackPageNavigation() {
@@ -174,17 +290,46 @@ export class NSLocationStrategy extends LocationStrategy {
return this._isPageNavigationBack;
}
- public _beginPageNavigation(): NavigationOptions {
+ public _beginModalNavigation(): void {
+ routerLog("NSLocationStrategy._beginModalNavigation()");
+ const lastState = this.peekState(this.currentOutlet);
+
+ if (lastState) {
+ lastState.isModalNavigation = true;
+ }
+
+ this._isModalNavigation = true;
+ }
+
+ public _beginCloseModalNavigation(): void {
+ routerLog("NSLocationStrategy.startCloseModal()");
+ if (this._isModalClosing) {
+ throw new Error("Calling startCloseModal while closing modal.");
+ }
+ this._isModalClosing = true;
+ }
+
+ public _finishCloseModalNavigation() {
+ routerLog("NSLocationStrategy.finishCloseModalNavigation()");
+ if (!this._isModalClosing) {
+ throw new Error("Calling startCloseModal while not closing modal.");
+ }
+ this._isModalClosing = false;
+ }
+
+ public _beginPageNavigation(name: string): NavigationOptions {
routerLog("NSLocationStrategy._beginPageNavigation()");
- const lastState = this.peekState();
+ const lastState = this.peekState(name);
if (lastState) {
lastState.isPageNavigation = true;
}
+ this.currentOutlet = name;
+
const navOptions = this._currentNavigationOptions || defaultNavOptions;
if (navOptions.clearHistory) {
routerLog("NSLocationStrategy._beginPageNavigation clearing states history");
- this.states = [lastState];
+ this.statesByOutlet[name] = [lastState];
}
this._currentNavigationOptions = undefined;
@@ -201,7 +346,7 @@ export class NSLocationStrategy extends LocationStrategy {
`${JSON.stringify(this._currentNavigationOptions)})`);
}
- public _getStates(): Array {
- return this.states.slice();
+ public _getStates(): { [key: string]: Array } {
+ return this.statesByOutlet;
}
}
diff --git a/nativescript-angular/router/ns-route-reuse-strategy.ts b/nativescript-angular/router/ns-route-reuse-strategy.ts
index d6b489180..e9b425020 100644
--- a/nativescript-angular/router/ns-route-reuse-strategy.ts
+++ b/nativescript-angular/router/ns-route-reuse-strategy.ts
@@ -12,6 +12,7 @@ import {
interface CacheItem {
key: string;
state: DetachedRouteHandle;
+ isModal: boolean;
}
/**
@@ -48,6 +49,36 @@ class DetachedStateCache {
destroyComponentRef(state.componentRef);
}
}
+
+ public clearModalCache() {
+ let removedItemsCount = 0;
+ const hasModalPages = this.cache.some(cacheItem => {
+ return cacheItem.isModal;
+ });
+
+ if (hasModalPages) {
+ let modalCacheCleared = false;
+
+ while (!modalCacheCleared) {
+ let cacheItem = this.peek();
+ const state = cacheItem.state;
+
+ if (!state.componentRef) {
+ throw new Error("No componentRef found in DetachedRouteHandle");
+ }
+
+ destroyComponentRef(state.componentRef);
+ if (cacheItem.isModal) {
+ modalCacheCleared = true;
+ }
+
+ this.pop();
+ removedItemsCount++;
+ }
+ }
+
+ log(`DetachedStateCache.clearModalCache() ${removedItemsCount} items will be destroyed`);
+ }
}
/**
@@ -57,7 +88,7 @@ class DetachedStateCache {
*/
@Injectable()
export class NSRouteReuseStrategy implements RouteReuseStrategy {
- private cache: DetachedStateCache = new DetachedStateCache();
+ private cacheByOutlet: { [key: string]: DetachedStateCache } = {};
constructor(private location: NSLocationStrategy) { }
@@ -77,9 +108,14 @@ export class NSRouteReuseStrategy implements RouteReuseStrategy {
shouldAttach(route: ActivatedRouteSnapshot): boolean {
route = findTopActivatedRouteNodeForOutlet(route);
+ const cache = this.cacheByOutlet[route.outlet];
+ if (!cache) {
+ return false;
+ }
+
const key = getSnapshotKey(route);
const isBack = this.location._isPageNavigatingBack();
- const shouldAttach = isBack && this.cache.peek().key === key;
+ const shouldAttach = isBack && cache.peek().key === key;
log(`shouldAttach isBack: ${isBack} key: ${key} result: ${shouldAttach}`);
@@ -92,12 +128,20 @@ export class NSRouteReuseStrategy implements RouteReuseStrategy {
const key = getSnapshotKey(route);
log(`store key: ${key}, state: ${state}`);
+ const cache = this.cacheByOutlet[route.outlet] = this.cacheByOutlet[route.outlet] || new DetachedStateCache();
+
if (state) {
- this.cache.push({ key, state });
+ let isModal = false;
+ if (this.location._isModalNavigation) {
+ isModal = true;
+ this.location._isModalNavigation = false;
+ }
+
+ cache.push({ key, state, isModal });
} else {
- const topItem = this.cache.peek();
+ const topItem = cache.peek();
if (topItem.key === key) {
- this.cache.pop();
+ cache.pop();
} else {
throw new Error("Trying to pop from DetachedStateCache but keys don't match. " +
`expected: ${topItem.key} actual: ${key}`);
@@ -108,9 +152,14 @@ export class NSRouteReuseStrategy implements RouteReuseStrategy {
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
route = findTopActivatedRouteNodeForOutlet(route);
+ const cache = this.cacheByOutlet[route.outlet];
+ if (!cache) {
+ return null;
+ }
+
const key = getSnapshotKey(route);
const isBack = this.location._isPageNavigatingBack();
- const cachedItem = this.cache.peek();
+ const cachedItem = cache.peek();
let state = null;
if (isBack && cachedItem && cachedItem.key === key) {
@@ -136,8 +185,20 @@ export class NSRouteReuseStrategy implements RouteReuseStrategy {
return shouldReuse;
}
- clearCache() {
- this.cache.clear();
+ clearCache(outletName: string) {
+ const cache = this.cacheByOutlet[outletName];
+
+ if (cache) {
+ cache.clear();
+ }
+ }
+
+ clearModalCache(outletName: string) {
+ const cache = this.cacheByOutlet[outletName];
+
+ if (cache) {
+ cache.clearModalCache();
+ }
}
}
diff --git a/nativescript-angular/router/page-router-outlet.ts b/nativescript-angular/router/page-router-outlet.ts
index 4db554d51..eb5950558 100644
--- a/nativescript-angular/router/page-router-outlet.ts
+++ b/nativescript-angular/router/page-router-outlet.ts
@@ -2,7 +2,7 @@ import {
Attribute, ChangeDetectorRef,
ComponentFactory, ComponentFactoryResolver, ComponentRef,
Directive, Inject, InjectionToken, Injector,
- OnDestroy, OnInit, EventEmitter, Output,
+ OnDestroy, EventEmitter, Output,
Type, ViewContainerRef, ElementRef
} from "@angular/core";
import {
@@ -102,7 +102,7 @@ function routeToString(activatedRoute: ActivatedRoute | ActivatedRouteSnapshot):
}
@Directive({ selector: "page-router-outlet" }) // tslint:disable-line:directive-selector
-export class PageRouterOutlet implements OnDestroy, OnInit { // tslint:disable-line:directive-class-suffix
+export class PageRouterOutlet implements OnDestroy { // tslint:disable-line:directive-class-suffix
private activated: ComponentRef | null = null;
private _activatedRoute: ActivatedRoute | null = null;
private detachedLoaderFactory: ComponentFactory;
@@ -161,28 +161,10 @@ export class PageRouterOutlet implements OnDestroy, OnInit { // tslint:disable-l
this.detachedLoaderFactory = resolver.resolveComponentFactory(DetachedLoader);
}
- ngOnInit(): void {
- if (this.isActivated) {
- return;
- }
-
- // If the outlet was not instantiated at the time the route got activated we need to populate
- // the outlet when it is initialized (ie inside a NgIf)
- const context = this.parentContexts.getContext(this.name);
- if (!context || !context.route) {
- return;
- }
-
- if (context.attachRef) {
- // `attachRef` is populated when there is an existing component to mount
- this.attach(context.attachRef, context.route);
- } else {
- // otherwise the component defined in the configuration is created
- this.activateWith(context.route, context.resolver || null);
- }
- }
-
ngOnDestroy(): void {
+ // Clear accumulated modal view page cache when page-router-outlet
+ // destroyed on modal view closing
+ this.routeReuseStrategy.clearModalCache(this.name);
this.parentContexts.onChildOutletDestroyed(this.name);
}
@@ -267,7 +249,7 @@ export class PageRouterOutlet implements OnDestroy, OnInit { // tslint:disable-l
loadedResolver: ComponentFactoryResolver
): void {
log("PageRouterOutlet.activate() forward navigation - " +
- "create detached loader in the loader container");
+ "create detached loader in the loader container");
const factory = this.getComponentFactory(activatedRoute, loadedResolver);
const page = this.pageFactory({
@@ -304,17 +286,17 @@ export class PageRouterOutlet implements OnDestroy, OnInit { // tslint:disable-l
page.on(Page.navigatedFromEvent, (global).Zone.current.wrap((args: NavigatedData) => {
if (args.isBackNavigation) {
- this.locationStrategy._beginBackPageNavigation();
+ this.locationStrategy._beginBackPageNavigation(this.name);
this.locationStrategy.back();
}
}));
- const navOptions = this.locationStrategy._beginPageNavigation();
+ const navOptions = this.locationStrategy._beginPageNavigation(this.name);
// Clear refCache if navigation with clearHistory
if (navOptions.clearHistory) {
const clearCallback = () => setTimeout(() => {
- this.routeReuseStrategy.clearCache();
+ this.routeReuseStrategy.clearCache(this.name);
page.off(Page.navigatedToEvent, clearCallback);
});
diff --git a/ng-sample/.vscode/launch.json b/ng-sample/.vscode/launch.json
index a12095658..ee3fe690b 100644
--- a/ng-sample/.vscode/launch.json
+++ b/ng-sample/.vscode/launch.json
@@ -1,72 +1,58 @@
{
- "version": "0.2.0",
- "configurations": [
- {
- "name": "Sync on iOS",
- "type": "nativescript",
- "platform": "ios",
- "request": "launch",
- "appRoot": "${workspaceRoot}",
- "sourceMaps": true,
- "diagnosticLogging": false,
- "emulator": false,
- "rebuild": false,
- "syncAllFiles": false
- },
- {
- "name": "Launch on iOS",
- "type": "nativescript",
- "platform": "ios",
- "request": "launch",
- "appRoot": "${workspaceRoot}",
- "sourceMaps": true,
- "diagnosticLogging": false,
- "emulator": false,
- "rebuild": true,
- "stopOnEntry": true
- },
- {
- "name": "Attach on iOS",
- "type": "nativescript",
- "platform": "ios",
- "request": "attach",
- "appRoot": "${workspaceRoot}",
- "sourceMaps": true,
- "diagnosticLogging": false,
- "emulator": false
- },
- {
- "name": "Sync on Android",
- "type": "nativescript",
- "platform": "android",
- "request": "launch",
- "appRoot": "${workspaceRoot}",
- "sourceMaps": true,
- "diagnosticLogging": false,
- "emulator": false,
- "rebuild": false
- },
- {
- "name": "Launch on Android",
- "type": "nativescript",
- "platform": "android",
- "request": "launch",
- "appRoot": "${workspaceRoot}",
- "sourceMaps": true,
- "diagnosticLogging": false,
- "emulator": false,
- "rebuild": true,
- "stopOnEntry": true
- },
- {
- "name": "Attach on Android",
- "type": "nativescript",
- "platform": "android",
- "request": "attach",
- "appRoot": "${workspaceRoot}",
- "sourceMaps": true,
- "diagnosticLogging": false,
- "emulator": false
- }
- ]
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Launch on iOS",
+ "type": "nativescript",
+ "request": "launch",
+ "platform": "ios",
+ "appRoot": "${workspaceRoot}",
+ "sourceMaps": true,
+ "stopOnEntry": false,
+ "tnsArgs": [
+ "--syncAllFiles"
+ ],
+ "watch": true
+ },
+ {
+ "name": "Attach on iOS",
+ "type": "nativescript",
+ "request": "attach",
+ "platform": "ios",
+ "appRoot": "${workspaceRoot}",
+ "sourceMaps": true,
+ "tnsArgs": [
+ "--syncAllFiles"
+ ],
+ "watch": false
+ },
+ {
+ "name": "Launch on Android",
+ "type": "nativescript",
+ "request": "launch",
+ "platform": "android",
+ "appRoot": "${workspaceRoot}",
+ "sourceMaps": true,
+ "stopOnEntry": false,
+ "tnsArgs": [
+ "--syncAllFiles"
+ ],
+ "watch": true
+ },
+ {
+ "name": "Attach on Android",
+ "type": "nativescript",
+ "request": "attach",
+ "platform": "android",
+ "appRoot": "${workspaceRoot}",
+ "sourceMaps": true,
+ "tnsArgs": [
+ "--syncAllFiles"
+ ],
+ "watch": false
+ }
+ ]
}
\ No newline at end of file
diff --git a/ng-sample/app/app.ts b/ng-sample/app/app.ts
index 666a570e5..eedfe1344 100644
--- a/ng-sample/app/app.ts
+++ b/ng-sample/app/app.ts
@@ -45,11 +45,15 @@ import { ImageTest } from "./examples/image/image-test";
import { HttpTest } from "./examples/http/http-test";
import { HttpClientTest } from "./examples/http-client/http-client-test";
import { ActionBarTest } from "./examples/action-bar/action-bar-test";
-import { ModalTest } from "./examples/modal/modal-test";
-import { ModalNestedTest } from "./examples/modal/modal-nested-test";
import { PlatfromDirectivesTest } from "./examples/platform-directives/platform-directives-test";
import { LivesyncApp } from "./examples/livesync-test/livesync-test-app";
+// modal
+import { ModalTest } from "./examples/modal/modal-test";
+import { ModalNestedTest } from "./examples/modal/modal-nested-test";
+import { ModalRouterOutletTest } from "./examples/modal/modal-router-outlet-test";
+import { ModalPageRouterOutletTest } from "./examples/modal/modal-page-router-outlet-test";
+
// new router
import { RouterOutletAppComponent } from "./examples/router/router-outlet-test";
import { PageRouterOutletAppComponent } from "./examples/router/page-router-outlet-test";
@@ -82,7 +86,7 @@ import { AnimationStatesMultiTest } from "./examples/animation/animation-states-
],
providers: [],
})
-class ExampleModule {}
+class ExampleModule { }
function makeExampleModule(componentType) {
let imports: any[] = [NativeScriptAnimationsModule, ExampleModule];
@@ -112,7 +116,7 @@ function makeExampleModule(componentType) {
providers,
exports,
})
- class ExampleModuleForComponent {}
+ class ExampleModuleForComponent { }
return ExampleModuleForComponent;
}
@@ -188,3 +192,6 @@ onAfterLivesync.subscribe(({ moduleRef, error }) => {
// platformNativeScriptDynamic().bootstrapModule(makeExampleModule(LivesyncApp));
// console.log("APP RESTART!!!! !!!");
// platformNativeScriptDynamic().bootstrapModule(makeExampleModule(ModalTest));
+// platformNativeScriptDynamic().bootstrapModule(makeExampleModule(ModalNestedTest));
+// platformNativeScriptDynamic().bootstrapModule(makeExampleModule(ModalRouterOutletTest));
+platformNativeScriptDynamic().bootstrapModule(makeExampleModule(ModalPageRouterOutletTest));
diff --git a/ng-sample/app/examples/modal/modal-nested-test.ts b/ng-sample/app/examples/modal/modal-nested-test.ts
index 0330d5525..d1ae043f2 100644
--- a/ng-sample/app/examples/modal/modal-nested-test.ts
+++ b/ng-sample/app/examples/modal/modal-nested-test.ts
@@ -17,7 +17,6 @@ export class ModalNestedTest {
];
static exports = [
- ModalContent,
ModalTest
];
diff --git a/ng-sample/app/examples/modal/modal-page-router-outlet-test.ts b/ng-sample/app/examples/modal/modal-page-router-outlet-test.ts
new file mode 100644
index 000000000..0477c8289
--- /dev/null
+++ b/ng-sample/app/examples/modal/modal-page-router-outlet-test.ts
@@ -0,0 +1,47 @@
+import { Component, ViewContainerRef } from "@angular/core";
+import * as dialogs from "ui/dialogs";
+import { ModalDialogService, ModalDialogOptions } from "nativescript-angular/directives/dialogs";
+import { FirstComponent, SecondComponent, ThirdComponent, PageRouterOutletAppComponent } from "../router/page-router-outlet-test";
+
+@Component({
+ selector: "modal-router-outlet-test",
+ template: `
+
+
+
+
+
+
+
+ `
+})
+export class ModalPageRouterOutletTest {
+
+ public result: string = "result";
+
+ constructor(private modal: ModalDialogService, private vcRef: ViewContainerRef) { }
+
+ static entries = [
+ PageRouterOutletAppComponent,
+ ];
+
+ static exports = [
+ FirstComponent,
+ SecondComponent,
+ ThirdComponent
+ ];
+
+ static routes = PageRouterOutletAppComponent.routes;
+
+ public showModal(fullscreen: boolean) {
+ const options: ModalDialogOptions = {
+ fullscreen: fullscreen,
+ viewContainerRef: this.vcRef
+ };
+
+ this.modal.showModal(PageRouterOutletAppComponent, options).then((res: string) => {
+ this.result = res || "empty result";
+ });
+ }
+
+}
diff --git a/ng-sample/app/examples/modal/modal-router-outlet-test.ts b/ng-sample/app/examples/modal/modal-router-outlet-test.ts
new file mode 100644
index 000000000..9bdac0d99
--- /dev/null
+++ b/ng-sample/app/examples/modal/modal-router-outlet-test.ts
@@ -0,0 +1,46 @@
+import { Component, ViewContainerRef } from "@angular/core";
+import * as dialogs from "ui/dialogs";
+import { ModalDialogService, ModalDialogOptions } from "nativescript-angular/directives/dialogs";
+import { FirstComponent, SecondComponent, RouterOutletAppComponent } from "../router/router-outlet-test";
+
+@Component({
+ selector: "modal-router-outlet-test",
+ template: `
+
+
+
+
+
+
+
+ `
+})
+export class ModalRouterOutletTest {
+
+ public result: string = "result";
+
+ constructor(private modal: ModalDialogService, private vcRef: ViewContainerRef) { }
+
+ static entries = [
+ RouterOutletAppComponent,
+ ];
+
+ static exports = [
+ FirstComponent,
+ SecondComponent
+ ];
+
+ static routes = RouterOutletAppComponent.routes;
+
+ public showModal(fullscreen: boolean) {
+ const options: ModalDialogOptions = {
+ fullscreen: fullscreen,
+ viewContainerRef: this.vcRef
+ };
+
+ this.modal.showModal(RouterOutletAppComponent, options).then((res: string) => {
+ this.result = res || "empty result";
+ });
+ }
+
+}
diff --git a/ng-sample/app/examples/modal/modal-test.ts b/ng-sample/app/examples/modal/modal-test.ts
index edfebf4fc..5bc742b10 100644
--- a/ng-sample/app/examples/modal/modal-test.ts
+++ b/ng-sample/app/examples/modal/modal-test.ts
@@ -31,9 +31,7 @@ export class ModalTest {
ModalContent
];
- static exports = [
- ModalContent
- ];
+ static exports = [];
public showModal(fullscreen: boolean) {
const options: ModalDialogOptions = {
diff --git a/ng-sample/app/examples/router/page-router-outlet-test.ts b/ng-sample/app/examples/router/page-router-outlet-test.ts
index 28261d6b3..9ce54352f 100644
--- a/ng-sample/app/examples/router/page-router-outlet-test.ts
+++ b/ng-sample/app/examples/router/page-router-outlet-test.ts
@@ -5,7 +5,6 @@ import { Page } from "ui/page";
import { Observable } from "rxjs";
import { map } from "rxjs/operators";
-
@Component({
selector: "first",
styleUrls: ["examples/router/styles.css"],
@@ -19,7 +18,7 @@ import { map } from "rxjs/operators";
`
})
-class FirstComponent implements OnInit, OnDestroy {
+export class FirstComponent implements OnInit, OnDestroy {
constructor(page: Page) {
console.log("FirstComponent.constructor() page: " + page);
}
@@ -47,7 +46,7 @@ class FirstComponent implements OnInit, OnDestroy {
`
})
-class SecondComponent implements OnInit, OnDestroy {
+export class SecondComponent implements OnInit, OnDestroy {
public id: Observable;
constructor(private location: Location, route: ActivatedRoute, page: Page) {
console.log("SecondComponent.constructor() page: " + page);
@@ -81,7 +80,7 @@ class SecondComponent implements OnInit, OnDestroy {
`
})
-class ThirdComponent implements OnInit, OnDestroy {
+export class ThirdComponent implements OnInit, OnDestroy {
public id: Observable;
constructor(private location: Location, route: ActivatedRoute, page: Page) {
console.log("ThirdComponent.constructor() page: " + page);
diff --git a/ng-sample/app/examples/router/router-outlet-test.ts b/ng-sample/app/examples/router/router-outlet-test.ts
index 04e82388a..90d37c7dc 100644
--- a/ng-sample/app/examples/router/router-outlet-test.ts
+++ b/ng-sample/app/examples/router/router-outlet-test.ts
@@ -10,7 +10,7 @@ import { map } from "rxjs/operators";
`
})
-class FirstComponent implements OnInit, OnDestroy {
+export class FirstComponent implements OnInit, OnDestroy {
ngOnInit() {
console.log("FirstComponent - ngOnInit()");
}
@@ -28,7 +28,7 @@ class FirstComponent implements OnInit, OnDestroy {
`
})
-class SecondComponent implements OnInit, OnDestroy {
+export class SecondComponent implements OnInit, OnDestroy {
id;
constructor(route: ActivatedRoute) {
this.id = route.params.pipe(map(r => r["id"]));
@@ -49,8 +49,14 @@ class SecondComponent implements OnInit, OnDestroy {
template: `
-
-
+
+