Skip to content

Commit 0c2e9b3

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

File tree

9 files changed

+116
-29
lines changed

9 files changed

+116
-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

+58-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,8 @@ 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";
43+
import { Page } from "tns-core-modules/ui/page";
4244

4345
export const onBeforeLivesync = new EventEmitter<NgModuleRef<any>>();
4446
export const onAfterLivesync = new EventEmitter<{ moduleRef?: NgModuleRef<any>; error?: Error }>();
@@ -55,6 +57,7 @@ export interface AppOptions {
5557
bootInExistingPage?: boolean;
5658
cssFile?: string;
5759
startPageActionBarHidden?: boolean;
60+
createFrameOnBootstrap?: boolean
5861
}
5962

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

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

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

163175
bootstrapLog(`Angular bootstrap bootstrap done. uptime: ${uptime()}`);
164-
rootContent = tempAppHostView.content;
165-
tempAppHostView.content = null;
166-
tempAppHostView.ngAppRoot = rootContent;
167-
rootContent.parentNode = tempAppHostView;
176+
177+
if (!autoCreateFrame) {
178+
rootContent = this.extractContentFromHost(tempAppHostView);
179+
}
180+
168181
lastBootstrappedModule = new WeakRef(moduleRef);
169182
},
170183
err => {
@@ -199,24 +212,33 @@ export class NativeScriptPlatformRef extends PlatformRef {
199212
@profile
200213
private livesync() {
201214
bootstrapLog("Angular livesync started.");
202-
203215
onBeforeLivesync.next(lastBootstrappedModule ? lastBootstrappedModule.get() : null);
204216

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

221+
if (autoCreateFrame) {
222+
const { page, frame } = this.createFrameAndPage(true);
223+
setRootPage(page);
224+
rootContent = frame;
225+
} else {
226+
// Create a temp page for root of the renderer
227+
tempAppHostView = new AppHostView();
228+
setRootPage(<any>tempAppHostView);
229+
}
230+
209231
let bootstrapPromiseCompleted = false;
210232
this._bootstrapper().then(
211233
moduleRef => {
212234
bootstrapPromiseCompleted = true;
213235
bootstrapLog("Angular livesync done.");
214236
onAfterLivesync.next({ moduleRef });
215237

216-
rootContent = tempAppHostView.content;
217-
tempAppHostView.content = null;
218-
tempAppHostView.ngAppRoot = rootContent;
219-
rootContent.parentNode = tempAppHostView;
238+
if (!autoCreateFrame) {
239+
rootContent = this.extractContentFromHost(tempAppHostView);
240+
}
241+
220242
lastBootstrappedModule = new WeakRef(moduleRef);
221243
},
222244
error => {
@@ -236,11 +258,11 @@ export class NativeScriptPlatformRef extends PlatformRef {
236258
bootstrapLog("livesync bootstrapAction called, draining micro tasks queue finished! Root: " + rootContent);
237259

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

243-
onAfterLivesync.next({ error: new Error(errorMessage) });
265+
onAfterLivesync.next({ error: new Error(result) });
244266
}
245267

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

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)