Angular Bootstrap
This article will cover in detail the process of bootstrapping an Angular application.
The Bootstrap Process
A traditional NativeScript application starts by initializing
global objects, setting up global CSS rules, creating, and
navigating to the main page. Angular does not care about any of
that -- all it needs is a place in the DOM to attach to. Of
course, Angular applications need to take care of their own
initialization: modules, components, directives, routes, DI
providers. A NativeScript Angular app needs to make both
paradigms work together, so we provide a wrapper platform
object, platformNativeScriptDynamic
, that sets up a
NativeScript application and can bootstrap the Angular framework
in a default location on the main UI page.
platformNativeScriptDynamic().bootstrapModule(AppModule);
One of our major design goals here is to provide virtually the
same interface as the default Angular
bootstrap
routine, so that people familiar with the
web version of Angular get productive with as little friction as
possible.
NativeScript Application Options
Application options in NativeScript are configured at the time
the application boots. That could be problematic for Angular
apps since the usual application start up process is hidden
inside the platformNativeScriptDynamic
black box.
To allow for customizations, we introduced an additional
AppOptions
parameter to the platform initialization
function that lets you preconfigure certain aspects of your
application behavior. At the moment those are:
-
cssFile
: overrides the path to the file containing global CSS rules that are applied to all visual objects in the application. The default path isapp.css
. -
createFrameOnBootstrap
: In cases where your application does not usepage-router-outlet
, you will not get the defaultPage
andFrame
, which means you will not be able to inject them in your components or show theActionBar
. There is a specialcreateFrameOnBootstrap
boolean option you can pass on bootstrap to make things as before 4.0.0:
platformNativeScriptDynamic({ createFrameOnBootstrap: true });
Customizing DI Providers
Many aspects of Angular applications are configured through the dependency injection (DI) system. NgModule's are usually the tool that lets you configure DI providers and exposes them to all application objects. Multiple Angular libraries, such as the router and the http client come with their own modules that register providers. NativeScript provides wrappers for the built-in modules (router, forms, HTTP) that should be used in mobile apps:
import { platformNativeScriptDynamic, NativeScriptModule } from "nativescript-angular/platform";
import { NgModule } from "@angular/core";
import { NativeScriptRouterModule } from "nativescript-angular/router";
import { NativeScriptHttpModule } from "nativescript-angular/http";
import { NativeScriptFormsModule } from "nativescript-angular/forms";
import { routes } from "./app.routes";
import { AppComponent } from "./app.component";
@NgModule({
declarations: [
AppComponent,
],
bootstrap: [AppComponent],
imports: [
NativeScriptModule,
NativeScriptHttpModule,
NativeScriptRouterModule,
NativeScriptRouterModule.forRoot(routes),
],
})
class AppModule {}
platformNativeScriptDynamic().bootstrapModule(AppModule);
For an in-depth guide to dependency injection in Angular, please review the Dependency Injection in Angular blog post.
Objects Injected by the Platform
The DI system plays a central part in Angular apps, and it makes
sense to use it to expose certain platform objects to client
code. That makes accessing them as simple as declaring a
constructor parameter of the specified type. For example, here
is how the component below gets an instance of the native
Page
object:
@Component({
selector: "user-details",
template: "..."
})
export class UserDetailsView {
constructor(private page: Page) {
}
}
Autoinjected objects
-
"ui/page".Page
: the native page the component renders on. The router implementation takes care to inject the correct instance when loading components on different pages. -
"platform".Device
: contains information about the device the application is running on.
Advanced Bootstrap
Certain application scenarios may require bootstrapping an Angular app in a preexisting NativeScript application. The need to do that usually arises in automated tests that need to create and destroy applications in different setups. Advanced bootstraps could also be useful when migrating vanilla NativeScript applications to Angular -- you can start the migration by integrating Angular and implementing new features with it, then start migrating old features one at a time.
The advanced bootstrap API entry point is again our friend the
platformNativeScriptDynamic
factory function, but
this time you need to pass the
bootInExistingPage
application option. You will
also need a DI provider that will return the visual element that
will serve as the application root view. Here is how a typical
bootstrap looks like:
const root = new StackLayout();
const rootViewProvider = {provide: APP_ROOT_VIEW, useValue: root};
@NgModule({
//...
providers: [
rootViewProvider,
]
})
class AdvancedBootstrapModule {}
platformNativeScriptDynamic({bootInExistingPage: true}).bootstrapModule(AdvancedBootstrapModule);
Conclusion
Bootstrapping a mobile Angular application should look almost identical to web application bootstraps. Most projects will never need to go beyond customizing DI providers or importing NgModule's, yet the customization mechanisms are there for the advanced use cases.