Our website is made possible by displaying online advertisements to our visitors. Please consider supporting us by disabling your ad blocker.

Nested Routing In A NativeScript Angular Application For Android And iOS

TwitterFacebookRedditLinkedInHacker News

When building mobile applications you’ll often find yourself needing to create child components. What do I mean by child components? Take for example a mobile application with two different screen groupings, one where the user is not signed in and the other where the user is signed in. In each of these groupings you could have multiple screens where the user is signed in and multiple screens where the user is not signed in. Each screen under the parent grouping can be considered a child component and they could possibly share a template from the parent. These child components often require nested routing to occur for a successful navigation.

We’re going to see how to create nested routes in a NativeScript mobile application built with Angular. You’ll see that things aren’t much different from creating standard routes in an Angular application.

The application we build will be very simple. We’ll have two parent components where one of the parent components has two child components. The other parent will have no child components. If you remember my work from AngularJS, you’ll remember I did something similar with nested states and the UI-Router. AngularJS is now ancient technology so we need to see how to do this with the latest Angular.

NativeScript Angular Nested Routes

For simplicity, we’ll create a fresh project and work from that. With NativeScript installed, from the Command Prompt (Windows) or Terminal (Mac and Linux), execute the following:

tns create NestedProject --ng

In later versions of NativeScript, we no longer need to add build platforms for Android and iOS. This is done automatically at build and run time.

With the base project created we can add a few components. If you’re using a Mac or Linux computer, execute the following from the command line:

mkdir -p app/components/parent
mkdir -p app/components/otherparent
mkdir -p app/copmonents/child
mkdir -p app/components/otherchild
touch app/components/parent/parent.component.ts
touch app/components/parent/parent.component.html
touch app/components/otherparent/otherparent.component.ts
touch app/components/otherparent/otherparent.component.html
touch app/components/child/child.component.ts
touch app/components/child/child.component.html
touch app/components/otherchild/otherchild.component.ts
touch app/components/otherchild/otherchild.component.html

If you’re on Windows, you can create each of the above files and directories manually.

Before we start creating each of the application screens, we should probably define them as routes and bootstrap them in the application. This needs to be done in two different files, but can vary depending on your project setup or version. Open the project’s app/app.routing.ts file and include the following code:

import { NgModule } from "@angular/core";
import { NativeScriptRouterModule } from "nativescript-angular/router";
import { Routes } from "@angular/router";

import { ParentComponent } from "./components/parent/parent.component";
import { OtherParentComponent } from "./components/otherparent/otherparent.component";
import { ChildComponent } from "./components/child/child.component";
import { OtherChildComponent } from "./components/otherchild/otherchild.component";

const routes: Routes = [
    { path: "", component: ParentComponent,
        children: [
            { path: "", component: ChildComponent },
            { path: "other", component: OtherChildComponent },
        ]
    },
    { path: "otherparent", component: OtherParentComponent }
];

@NgModule({
    imports: [NativeScriptRouterModule.forRoot(routes)],
    exports: [NativeScriptRouterModule]
})
export class AppRoutingModule { }

What is important in the above are the route definitions. Two parent routes are defined, one with a default path (the empty one), and one that doesn’t act as the default path. The default route has two children, one of which is the default child. Just like with the parent, the default child is the one with the empty path. This rule applies for any routing in Angular.

When it comes to navigation, imagine that routing happens like this:

/ -> ChildComponent
/other -> OtherChildComponent
otherparent -> OtherParentComponent

Default routes can be represented by the slash character. Navigating to the default route will actually navigate to the default child in this scenario. The other parent route is not a default route so it has no leading slash.

With those routes defined, we need to make a few changes to the main @NgModules block of our application. Open the project’s app/app.module.ts file and include the following code:

import { NgModule, NO_ERRORS_SCHEMA } from "@angular/core";
import { NativeScriptModule } from "nativescript-angular/nativescript.module";
import { AppRoutingModule } from "./app.routing";
import { AppComponent } from "./app.component";

import { ParentComponent } from "./components/parent/parent.component";
import { OtherParentComponent } from "./components/otherparent/otherparent.component";
import { ChildComponent } from "./components/child/child.component";
import { OtherChildComponent } from "./components/otherchild/otherchild.component";

@NgModule({
    bootstrap: [
        AppComponent
    ],
    imports: [
        NativeScriptModule,
        AppRoutingModule
    ],
    declarations: [
        AppComponent,
        ParentComponent,
        OtherParentComponent,
        ChildComponent,
        OtherChildComponent
    ],
    providers: [],
    schemas: [
        NO_ERRORS_SCHEMA
    ]
})
export class AppModule { }

In the above code, we’ve essentially imported the components and added them to the @NgModule block. At this point in time, the development process can start.

Per rules of NativeScript, the default page route will always pass through a <page-router-outlet> tag. This tag is found in the project’s app/app.component.html file like so:

<ActionBar title="{N} Nesting Example"></ActionBar>
<page-router-outlet></page-router-outlet>

Notice that this page has a navigation bar component.

Being that the ParentComponent and ChildComponent classes are our default pages, we should probably set them up, starting with the parent. Open the project’s app/components/parent/parent.component.ts file and include the following TypeScript code:

import { Component } from "@angular/core";

@Component({
    selector: "parent",
    templateUrl: "./components/parent/parent.component.html",
})
export class ParentComponent { }

Nothing special happening in the above, so let’s look at the HTML file that is paired with it. Open the project’s app/components/parent/parent.component.html file and include the following HTML markup:

<StackLayout>
    <Label text="Parent Component" class="h2"></Label>
    <router-outlet></router-outlet>
</StackLayout>

This is a pretty standard layout, but what is special here is the use of the <router-outlet> tags. These are not the same as the <page-router-outlet> tags that were seen previously. The <router-outlet> tags act as a pass-through for any child routes. This means that when we load our application, we’ll see the navigation bar, the parent component text, and whatever is in the child component.

So let’s look at that first child component.

Open the project’s app/components/child/child.component.ts file and include the following TypeScript code:

import { Component } from "@angular/core";
import { Router } from "@angular/router";

@Component({
    selector: "child",
    templateUrl: "./components/child/child.component.html",
})
export class ChildComponent {

    public constructor(private router: Router) {}

    public navigateToOtherChild() {
        this.router.navigate(["/other"]);
    }

    public navigateToOtherParent() {
        this.router.navigate(["otherparent"]);
    }

}

In the above we have two methods that will be used for navigation. One will navigate to the other child component, and one that will navigate to the other parent component which has no children. Remember what the route paths mean that were described earlier. With the TypeScript out of the way, open the project’s app/components/child/child.component.html file and include the following HTML markup:

<StackLayout>
    <Label text="Child Component" class="h3"></Label>
    <Button text="Navigate Other Child" (tap)="navigateToOtherChild()" class="btn btn-primary"></Button>
    <Button text="Navigate Other Parent" (tap)="navigateToOtherParent()" class="btn btn-primary"></Button>
</StackLayout>

In this child component we have text as well as two buttons. Each button will call the appropriate function for navigation. Think back to the animated image seen at the beginning of the tutorial. On the default screen you’ll see the navigation bar, the parent text, the child text, and the buttons for navigation. This is through nested routing.

So what does the other child component look like? Nothing special.

Open the project’s app/components/otherchild/otherchild.component.ts file and include the following TypeScript code:

import { Component } from "@angular/core";

@Component({
    selector: "otherchild",
    templateUrl: "./components/otherchild/otherchild.component.html",
})
export class OtherChildComponent { }

There is no special logic in the above TypeScript file. Instead let’s look at the HTML markup found in the project’s app/components/otherchild/otherchild.component.html file:

<StackLayout>
    <Label text="Other Component" class="h3"></Label>
</StackLayout>

There are no buttons in the above, just text to tell us what page we’re on. When navigating to this child, the parent text will still show, but the child views will be swapped out.

Let’s bring this to a close and take a look at our final route being the other parent route.

Open the project’s app/components/otherparent/otherparent.component.ts file and include the following TypeScript code:

import { Component } from "@angular/core";

@Component({
    selector: "otherparent",
    templateUrl: "./components/otherparent/otherparent.component.html",
})
export class OtherParentComponent { }

For this example there is no special logic for the above TypeScript file. The HTML file that follows is nothing special either, but within the project’s app/components/otherparent/otherparent.component.html file you should have the following:

<StackLayout>
    <Label text="Other Parent Component" class="h2"></Label>
</StackLayout>

At this point you should have a multiple route application that includes several child routes that share a parent template.

Conclusion

You just saw how to use nested routing to create parent and child pages for your NativeScript with Angular application. This is similar to my previous AngularJS article on the topic, but this time we’re using the latest Angular. To put things into context, my application, Solar Flare, uses nested routing for the authorized and unauthorized screens. The authorized screens share a parent route which includes a navigation drawer.

Nic Raboy

Nic Raboy

Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in C#, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Unity. Nic writes about his development experiences related to making web and mobile development easier to understand.