Skip to content

Commit 69770ea

Browse files
author
vakrilov
committed
feat: Added createFrameOnBootstrap bootstrap option for back compat
1 parent 70d5471 commit 69770ea

File tree

9 files changed

+115
-29
lines changed

9 files changed

+115
-29
lines changed

Diff for: e2e/single-page/app/app.component.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import { Component } from "@angular/core";
55
<GridLayout rows="* auto">
66
<router-outlet></router-outlet>
77
8-
<StackLayout class="nav" row="1">
8+
<FlexboxLayout class="nav" row="1">
99
<Button text="First" nsRouterLinkActive="active" nsRouterLink="/first"></Button>
1010
<Button text="Second(1)" nsRouterLinkActive="active" nsRouterLink="/second/1"></Button>
1111
<Button text="Second(2)" nsRouterLinkActive="active" [nsRouterLink]="['/second', '2' ]">
1212
</Button>
13-
</StackLayout>
13+
</FlexboxLayout>
1414
1515
</GridLayout>
1616
`

Diff for: e2e/single-page/app/app.css

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
vertical-align: bottom;
1010
padding: 4;
1111
background-color: lightblue;
12+
justify-content: space-around;
13+
align-content: center;
1214
}
1315

1416
.link {

Diff for: e2e/single-page/app/main.aot.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
import { platformNativeScript } from "nativescript-angular/platform-static";
22
import { AppModuleNgFactory } from "./app.module.ngfactory";
33

4-
platformNativeScript().bootstrapModuleFactory(AppModuleNgFactory);
4+
platformNativeScript({ createFrameOnBootstrap: true }).bootstrapModuleFactory(AppModuleNgFactory);

Diff for: e2e/single-page/app/main.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
import { platformNativeScriptDynamic } from "nativescript-angular/platform";
22
import { AppModule } from "./app.module";
33

4-
platformNativeScriptDynamic().bootstrapModule(AppModule);
4+
platformNativeScriptDynamic({ createFrameOnBootstrap: true }).bootstrapModule(AppModule);

Diff for: e2e/single-page/app/second/second.component.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,19 @@ import { Observable } from "rxjs/Observable";
1010
<ActionBar title="Second Title">
1111
<ActionItem text="ACTION2"></ActionItem>
1212
</ActionBar>
13+
14+
<ActionBarExtension *ngIf="(id$ | async) === 2">
15+
<ActionItem text="ADD" ios.position="right"></ActionItem>
16+
</ActionBarExtension>
17+
1318
<StackLayout>
14-
<Label [text]="'Second component: ' + (id$ | async)" class="title"></Label>
19+
<Label [text]="'Second Component: ' + (id$ | async)" class="title"></Label>
1520
</StackLayout>`
1621
})
1722
export class SecondComponent implements OnInit, OnDestroy {
1823
public id$: Observable<number>;
1924
constructor(route: ActivatedRoute) {
20-
this.id$ = route.params.map(r => r["id"]);
25+
this.id$ = route.params.map(r => +r["id"]);
2126
}
2227

2328
ngOnInit() {

Diff for: e2e/single-page/e2e/tests.e2e-spec.ts

+28-3
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,41 @@ import {
55
SearchOptions,
66
} from "nativescript-dev-appium";
77

8-
describe("Simple navigate and back", () => {
8+
describe("Single page app", () => {
99
let driver: AppiumDriver;
1010

1111
before(async () => {
1212
driver = await createDriver();
1313
await driver.resetApp();
1414
});
1515

16-
it("should find First", async () => {
17-
await assureFirstComponent(driver);
16+
it("should load first page", async () => {
17+
await driver.findElementByText("First Component", SearchOptions.exact);
18+
19+
// ActionBar Title and item
20+
await driver.findElementByText("First Title", SearchOptions.exact);
21+
await driver.findElementByText("ACTION1", SearchOptions.exact);
22+
});
23+
24+
it("should load second(1) page", async () => {
25+
await findAndClick(driver, "SECOND(1)")
26+
27+
await driver.findElementByText("Second Component: 1", SearchOptions.exact);
28+
29+
// ActionBar Title and item
30+
await driver.findElementByText("Second Title", SearchOptions.exact);
31+
await driver.findElementByText("ACTION2", SearchOptions.exact);
32+
});
33+
34+
it("should load second(2) page", async () => {
35+
await findAndClick(driver, "SECOND(2)")
36+
37+
await driver.findElementByText("Second Component: 1", SearchOptions.exact);
38+
39+
// ActionBar Title and items
40+
await driver.findElementByText("Second Title", SearchOptions.exact);
41+
await driver.findElementByText("ACTION2", SearchOptions.exact);
42+
await driver.findElementByText("ADD", SearchOptions.exact);
1843
});
1944
});
2045

Diff for: nativescript-angular/directives/action-bar.ts

+7
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ registerElement("NavigationButton", () => require("ui/action-bar").NavigationBut
9292
})
9393
export class ActionBarComponent {
9494
constructor(public element: ElementRef, private page: Page) {
95+
if (!this.page) {
96+
throw new Error("Inside ActionBarComponent but no Page found in DI.");
97+
}
98+
9599
if (isBlank(this.page.actionBarHidden)) {
96100
this.page.actionBarHidden = false;
97101
}
@@ -106,6 +110,9 @@ export class ActionBarComponent {
106110
})
107111
export class ActionBarScope { // tslint:disable-line:component-class-suffix
108112
constructor(private page: Page) {
113+
if (!this.page) {
114+
throw new Error("Inside ActionBarScope but no Page found in DI.");
115+
}
109116
}
110117

111118
public onNavButtonInit(navBtn: NavigationButtonDirective) {

Diff for: nativescript-angular/platform-common.ts

+57-19
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
import { DOCUMENT } from "@angular/common";
2424

2525
import { bootstrapLog, bootstrapLogError } from "./trace";
26-
import { defaultPageFactoryProvider, setRootPage } from "./platform-providers";
26+
import { defaultPageFactoryProvider, setRootPage, PageFactory, PAGE_FACTORY } from "./platform-providers";
2727
import { AppHostView } from "./app-host-view";
2828

2929
import {
@@ -39,6 +39,7 @@ import { TextView } from "tns-core-modules/ui/text-view";
3939

4040
import "nativescript-intl";
4141
import { Color, View } from "tns-core-modules/ui/core/view/view";
42+
import { Frame } from "tns-core-modules/ui/frame";
4243

4344
export const onBeforeLivesync = new EventEmitter<NgModuleRef<any>>();
4445
export const onAfterLivesync = new EventEmitter<{ moduleRef?: NgModuleRef<any>; error?: Error }>();
@@ -55,6 +56,7 @@ export interface AppOptions {
5556
bootInExistingPage?: boolean;
5657
cssFile?: string;
5758
startPageActionBarHidden?: boolean;
59+
createFrameOnBootstrap?: boolean;
5860
}
5961

6062
export type PlatformFactory = (extraProviders?: StaticProvider[]) => PlatformRef;
@@ -143,11 +145,20 @@ export class NativeScriptPlatformRef extends PlatformRef {
143145

144146
@profile
145147
private bootstrapNativeScriptApp() {
146-
// Create a temp page for root of the renderer
147-
const tempAppHostView = new AppHostView();
148-
setRootPage(<any>tempAppHostView);
148+
const autoCreateFrame = !!this.appOptions.createFrameOnBootstrap;
149+
let tempAppHostView: AppHostView;
149150
let rootContent: View;
150151

152+
if (autoCreateFrame) {
153+
const { page, frame } = this.createFrameAndPage(false);
154+
setRootPage(page);
155+
rootContent = frame;
156+
} else {
157+
// Create a temp page for root of the renderer
158+
tempAppHostView = new AppHostView();
159+
setRootPage(<any>tempAppHostView);
160+
}
161+
151162
bootstrapLog("NativeScriptPlatform bootstrap started.");
152163
const launchCallback = profile(
153164
"nativescript-angular/platform-common.launchCallback",
@@ -161,10 +172,11 @@ export class NativeScriptPlatformRef extends PlatformRef {
161172
bootstrapPromiseCompleted = true;
162173

163174
bootstrapLog(`Angular bootstrap bootstrap done. uptime: ${uptime()}`);
164-
rootContent = tempAppHostView.content;
165-
tempAppHostView.content = null;
166-
tempAppHostView.ngAppRoot = rootContent;
167-
rootContent.parentNode = tempAppHostView;
175+
176+
if (!autoCreateFrame) {
177+
rootContent = this.extractContentFromHost(tempAppHostView);
178+
}
179+
168180
lastBootstrappedModule = new WeakRef(moduleRef);
169181
},
170182
err => {
@@ -199,24 +211,33 @@ export class NativeScriptPlatformRef extends PlatformRef {
199211
@profile
200212
private livesync() {
201213
bootstrapLog("Angular livesync started.");
202-
203214
onBeforeLivesync.next(lastBootstrappedModule ? lastBootstrappedModule.get() : null);
204215

205-
const tempAppHostView = new AppHostView();
206-
setRootPage(<any>tempAppHostView);
216+
const autoCreateFrame = !!this.appOptions.createFrameOnBootstrap;
217+
let tempAppHostView: AppHostView;
207218
let rootContent: View;
208219

220+
if (autoCreateFrame) {
221+
const { page, frame } = this.createFrameAndPage(true);
222+
setRootPage(page);
223+
rootContent = frame;
224+
} else {
225+
// Create a temp page for root of the renderer
226+
tempAppHostView = new AppHostView();
227+
setRootPage(<any>tempAppHostView);
228+
}
229+
209230
let bootstrapPromiseCompleted = false;
210231
this._bootstrapper().then(
211232
moduleRef => {
212233
bootstrapPromiseCompleted = true;
213234
bootstrapLog("Angular livesync done.");
214235
onAfterLivesync.next({ moduleRef });
215236

216-
rootContent = tempAppHostView.content;
217-
tempAppHostView.content = null;
218-
tempAppHostView.ngAppRoot = rootContent;
219-
rootContent.parentNode = tempAppHostView;
237+
if (!autoCreateFrame) {
238+
rootContent = this.extractContentFromHost(tempAppHostView);
239+
}
240+
220241
lastBootstrappedModule = new WeakRef(moduleRef);
221242
},
222243
error => {
@@ -236,11 +257,11 @@ export class NativeScriptPlatformRef extends PlatformRef {
236257
bootstrapLog("livesync bootstrapAction called, draining micro tasks queue finished! Root: " + rootContent);
237258

238259
if (!bootstrapPromiseCompleted) {
239-
const errorMessage = "Livesync bootstrap promise didn't resolve";
240-
bootstrapLogError(errorMessage);
241-
rootContent = this.createErrorUI(errorMessage);
260+
const result = "Livesync bootstrap promise didn't resolve";
261+
bootstrapLogError(result);
262+
rootContent = this.createErrorUI(result);
242263

243-
onAfterLivesync.next({ error: new Error(errorMessage) });
264+
onAfterLivesync.next({ error: new Error(result) });
244265
}
245266

246267
applicationRerun({
@@ -254,4 +275,21 @@ export class NativeScriptPlatformRef extends PlatformRef {
254275
errorTextBox.color = new Color("red");
255276
return errorTextBox;
256277
}
278+
279+
private createFrameAndPage(isLivesync: boolean) {
280+
const frame = new Frame();
281+
const pageFactory: PageFactory = this.platform.injector.get(PAGE_FACTORY);
282+
const page = pageFactory({ isBootstrap: true, isLivesync });
283+
284+
frame.navigate({ create: () => { return page; } });
285+
return { page, frame };
286+
}
287+
288+
private extractContentFromHost(tempAppHostView: AppHostView) {
289+
const result = tempAppHostView.content;
290+
tempAppHostView.content = null;
291+
tempAppHostView.ngAppRoot = result;
292+
result.parentNode = tempAppHostView;
293+
return result;
294+
}
257295
}

Diff for: nativescript-angular/platform-providers.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,17 @@ export function getRootPage(): Page {
2121

2222
// Use an exported function to make the AoT compiler happy.
2323
export function getDefaultPage(): Page {
24+
const rootPage = getRootPage();
25+
if (rootPage instanceof Page) {
26+
return rootPage;
27+
}
28+
2429
const frame = topmost();
25-
return getRootPage() || (frame && frame.currentPage);
30+
if (frame && frame.currentPage) {
31+
return frame.currentPage;
32+
}
33+
34+
return null;
2635
}
2736

2837
export const defaultPageProvider = { provide: Page, useFactory: getDefaultPage };

0 commit comments

Comments
 (0)