🤖 Create a chatbot for your NativeScript app! Learn more at our upcoming webinar.

NativeScript Angular

NativeScript application architecture and lifecycle

The main building blocks of NativeScript applications with Angular are modules and components. The application module lets you manage the life cycle of your NativeScript apps from starting the application to storing user-defined settings.

Modules

Angular applications are modular. A module is a file containing a block of code dedicated to a single purpose. It exports a value that can be used by other parts of the application. For example:

export class AppComponent {}

The export statement is important as it makes the AppComponent accessible to other modules. The import clause is used to reference the AppComponent class from other modules:

import { Component } from '@angular/core';
import { AppComponent } from './app.component';

Some of the modules can depend on one or more separate modules. Modules installed as npm packages (like @angular/core in the above example) should be referenced without a path prefix. When we import from one of our own files, we prefix the module name with the file path. In this example, we specify a relative file path (./). That means the source module is in the same folder (./) as the module importing it.

Components

Components are the fundamental building blocks of NativeScript applications built with Angular. Every NativeScript application contains a set of components that define every UI element, screen or route. The application has a root component that contains all other components. The following constitutes a component:

  • A component knows how to interact with its host element.
  • A component knows how to render itself.
  • A component configures dependency injection.
  • A component has a well-defined public API of input and output properties.
  • A component has a well-defined lifecycle.
import { Component } from "@angular/core";

@Component({
    selector: "main-component",
    template: `
        <StackLayout>
            <Label text="Hello "></Label>
        </StackLayout>
    `
})
export class MainComponent {
    name: string;

    constructor() {
        this.name = "Angular!";
    }
}

Component metadata

The @Component decorator contains metadata describing how to create and present the component. Here are some of the configuration options:

  • selector - a CSS selector that tells Angular to create and insert an instance of this component where it finds the selector in parent component's template. For example:
<main-component></main-component>
  • template - A visual tree that represents the component view. Here you can use all NativeScript UI elements and custom defined UI components.
  • templateUrl - The address of a file where the component template is located.
  • styles - CSS directives that define the component style.
  • styleUrls - An array containing URLs of CSS files that define the component style.
  • animations - The animations associated with this component.
  • providers - an array of dependency injection providers for services that the component requires.

Component lifecycle

The component lifecycle is controlled by the Angular application. It creates, updates and destroys components. Lifecycle hooks are used to handle different events from the component lifecycle. Each hook method starts with the ng prefix. The following are some the component lifecycle methods:

  • ngOnInit - Called after all data-bound input methods are initialized.
  • ngOnChanges - Called after a data-bound property has been changed.
  • ngDoCheck - Detect and act upon changes that Angular can't or won't detect on its own. Called every change detection run.
  • ngOnDestroy - Called just before Angular destroys the component.

For a full list, see the official Angular Lifecycle Hooks docs.

Start application

The starting point of an Angular application is the platformNativeScriptDynamic().bootstrapModule() method. It takes the root module as an argument:

import { platformNativeScriptDynamic } from "nativescript-angular/platform";
import { AppModule } from "./app.module";

platformNativeScriptDynamic().bootstrapModule(AppModule).then(() => {
    console.log("The application is now running!");
}).catch((e) => {
    console.log("The application bootstrapping failed with error: " + e);
});

Use Application Events

NativeScript applications have the following life cycle events.

  • launch: This event is raised when application launch.
  • suspend: This event is raised when the application is suspended.
  • resume: This event is raised when the application is resumed after it has been suspended.
  • displayed: This event is raised when the UIelements are rendered.
  • orientationChanged: This event is raised when the device changes orientation.
  • exit: This event is raised when the application is about to exit.
  • lowMemory: This event is raised when the memory on the target device is low.
  • uncaughtError: This event is raised when an uncaught application error is present.
import { platformNativeScriptDynamic } from "nativescript-angular/platform";
import { AppModule } from "./app.module";
import { on as applicationOn, launchEvent, suspendEvent, resumeEvent, exitEvent, lowMemoryEvent, uncaughtErrorEvent, ApplicationEventData } from "tns-core-modules/application";

applicationOn(launchEvent, (args: ApplicationEventData) => {
    if (args.android) {
        // For Android applications, args.android is an android.content.Intent class.
        console.log("Launched Android application with the following intent: " + args.android + ".");
    } else if (args.ios !== undefined) {
        // For iOS applications, args.ios is NSDictionary (launchOptions).
        console.log("Launched iOS application with options: " + args.ios);
    }
});

applicationOn(suspendEvent, (args: ApplicationEventData) => {
    if (args.android) {
        // For Android applications, args.android is an android activity class.
        console.log("Activity: " + args.android);
    } else if (args.ios) {
        // For iOS applications, args.ios is UIApplication.
        console.log("UIApplication: " + args.ios);
    }
});

applicationOn(resumeEvent, (args: ApplicationEventData) => {
    if (args.android) {
        // For Android applications, args.android is an android activity class.
        console.log("Activity: " + args.android);
    } else if (args.ios) {
        // For iOS applications, args.ios is UIApplication.
        console.log("UIApplication: " + args.ios);
    }
});

applicationOn(exitEvent, (args: ApplicationEventData) => {
    if (args.android) {
        // For Android applications, args.android is an android activity class.
        console.log("Activity: " + args.android);
    } else if (args.ios) {
        // For iOS applications, args.ios is UIApplication.
        console.log("UIApplication: " + args.ios);
    }
});

applicationOn(lowMemoryEvent, (args: ApplicationEventData) => {
    if (args.android) {
        // For Android applications, args.android is an android activity class.
        console.log("Activity: " + args.android);
    } else if (args.ios) {
        // For iOS applications, args.ios is UIApplication.
        console.log("UIApplication: " + args.ios);
    }
});

applicationOn(uncaughtErrorEvent, (args: ApplicationEventData) => {
    if (args.android) {
        // For Android applications, args.android is an NativeScriptError.
        console.log("NativeScriptError: " + args.android);
    } else if (args.ios) {
        // For iOS applications, args.ios is NativeScriptError.
        console.log("NativeScriptError: " + args.ios);
    }
});
platformNativeScriptDynamic().bootstrapModule(AppModule);

Android Activity Events

NativeScript applications have the following Android specific activity events:

  • activityCreated: This event is raised when activity is created.
  • activityDestroyed: This event is raised when activity is destroyed.
  • activityStarted: This event is raised when activity is started.
  • activityPaused: This event is raised when activity is paused.
  • activityResumed: This event is raised when activity is resumed.
  • activityStopped: This event is raised when activity is stopped.
  • saveActivityState: This event is raised to retrieve per-instance state from an activity before being killed so that the state can be restored.
  • activityResult: This event is raised when an activity you launched exits, giving you the requestCode you started it with, the resultCode it returned, and any additional data from it.
  • activityBackPressed: This event is raised when the activity has detected the user's press of the back key.
import { platformNativeScriptDynamic } from "nativescript-angular/platform";
import { AppModule } from "./app.module";
import { android, AndroidApplication, AndroidActivityBundleEventData, AndroidActivityEventData, AndroidActivityResultEventData, AndroidActivityBackPressedEventData } from "tns-core-modules/application";

// Android activity events
if (android) {
    android.on(AndroidApplication.activityCreatedEvent, function (args: AndroidActivityBundleEventData) {
        console.log("Event: " + args.eventName + ", Activity: " + args.activity + ", Bundle: " + args.bundle);
    });

    android.on(AndroidApplication.activityDestroyedEvent, function (args: AndroidActivityEventData) {
        console.log("Event: " + args.eventName + ", Activity: " + args.activity);
    });

    android.on(AndroidApplication.activityStartedEvent, function (args: AndroidActivityEventData) {
        console.log("Event: " + args.eventName + ", Activity: " + args.activity);
    });

    android.on(AndroidApplication.activityPausedEvent, function (args: AndroidActivityEventData) {
        console.log("Event: " + args.eventName + ", Activity: " + args.activity);
    });

    android.on(AndroidApplication.activityResumedEvent, function (args: AndroidActivityEventData) {
        console.log("Event: " + args.eventName + ", Activity: " + args.activity);
    });

    android.on(AndroidApplication.activityStoppedEvent, function (args: AndroidActivityEventData) {
        console.log("Event: " + args.eventName + ", Activity: " + args.activity);
    });

    android.on(AndroidApplication.saveActivityStateEvent, function (args: AndroidActivityBundleEventData) {
        console.log("Event: " + args.eventName + ", Activity: " + args.activity + ", Bundle: " + args.bundle);
    });

    android.on(AndroidApplication.activityResultEvent, function (args: AndroidActivityResultEventData) {
        console.log("Event: " + args.eventName + ", Activity: " + args.activity +
            ", requestCode: " + args.requestCode + ", resultCode: " + args.resultCode + ", Intent: " + args.intent);
    });

    android.on(AndroidApplication.activityBackPressedEvent, function (args: AndroidActivityBackPressedEventData) {
        console.log("Event: " + args.eventName + ", Activity: " + args.activity);
        // Set args.cancel = true to cancel back navigation and do something custom.
    });
}
platformNativeScriptDynamic().bootstrapModule(AppModule);

iOS UIApplicationDelegate

In NativeScript, you can specify custom UIApplicationDelegate for the iOS application:

import { platformNativeScriptDynamic } from "nativescript-angular/platform";

import { AppModule } from "./app.module";

import { ios } from "tns-core-modules/application";
class MyDelegate extends UIResponder implements UIApplicationDelegate {
    public static ObjCProtocols = [UIApplicationDelegate];

    applicationDidFinishLaunchingWithOptions(application: UIApplication, launchOptions: NSDictionary<any, any>): boolean {
        console.log("applicationWillFinishLaunchingWithOptions: " + launchOptions)

        return true;
    }

    applicationDidBecomeActive(application: UIApplication): void {
        console.log("applicationDidBecomeActive: " + application)
    }
}
ios.delegate = MyDelegate;
platformNativeScriptDynamic().bootstrapModule(AppModule);

Note: If you’re using TypeScript in your NativeScript apps, you need to install the tns-platform-declarations plugin to add typings for native iOS APIs such as UIApplicationDelegate.

Persist and Restore Application Settings

To persist user-defined settings, you need to use the application-settings module. The application-settings module is a static singleton hash table that stores key-value pairs for the application.

The getter methods have two parameters: a key and an optional default value to return if the specified key does not exist. The setter methods have two required parameters: a key and value.

import { EventData } from "tns-core-modules/data/observable";
import * as applicationSettings from "tns-core-modules/application-settings";
// Event handler for Page "loaded" event attached in main-page.xml.
export function pageLoaded(args: EventData) {
    applicationSettings.setString("Name", "John Doe");
    console.log(applicationSettings.getString("Name"));// Prints "John Doe".
    applicationSettings.setBoolean("Married", false);
    console.log(applicationSettings.getBoolean("Married"));// Prints false.
    applicationSettings.setNumber("Age", 42);
    console.log(applicationSettings.getNumber("Age"));// Prints 42.
    console.log(applicationSettings.hasKey("Name"));// Prints true.
    applicationSettings.remove("Name");// Removes the Name entry.
    console.log(applicationSettings.hasKey("Name"));// Prints false.
}