Techumber
Home Blog Work

Navigation between pages in NativeScript using Angular 2 Routers

Published on July 18, 2016

In the previous post, we have seen how to build Side Drawer for a NativeScript application.

In that post, we are displaying the page names on SideDrawer menu but when you click on them it does nothing. We have to implement a navigation mechanism for the app.

To view the source code go here. To download the apk click here. or

If your were developing the app without Angular 2 you have to use ui/frame module.

example:

import frameModule = require("ui/frame");
var topmost = frameModule.topmost();
topmost.navigate("about-page");

Since we are developing the application using Angular 2 let’s take the advantage of it. We can use Angular 2 router concept to implement page navigation for NativeScript.

We will implement this on top of the previous code. To know how to get the code please go here and read Get GitUsers App section But you need to checkout v1.1 tag insted v1.0.

Angular Router for Component

In Angular 2 everything is a component. So when we want to go from one page to another page means that we are loading one component based the path match.

Note: We are using @angular/router v3. in this post. For the deprecated beta router please import nativescript-angular/router-deprecated

Adding About Component

In our previous app we have only user list component. Let’s create another component so that we can navigate between those two component.

components/about/about.component.ts

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

@Component({
  moduleId: module.id,
  selector: "about",
  templateUrl: "about.component.html"
})
export class AboutComponent implements OnInit {
  constructor() {}
  ngOnInit() {}
}

components/about/about.component.html

<label text="About Page Text goes here............." textWrap="true"></label>

Router Config

We have to tell angular which component should load into the view at what path or pattern.

To do so we will implement a RouterConfig.

import { RouterConfig } from "@angular/router";
import { nsProvideRouter } from "nativescript-angular/router";
import { userListComponent } from "../components/list/list.component";
import { AboutComponent } from "../components/about/about.component";

const routes: RouterConfig = [
  { path: "", redirectTo: "/list", terminal: true },
  { path: "list", component: userListComponent },
  { path: "about", component: AboutComponent }
];

export const APP_ROUTER_PROVIDERS = [
  nsProvideRouter(routes, { enableTracing: false })
];

Here we created a routers constant of Type RouterConfig. In this, we will set the path pattern to component name.

All component have been imported above.

We are exporting APP_ROUTER_PROVIDERS wich is an array of nsProvideRouters.

APP_ROUTER_PROVIDERS in BootStraping

Now, we need to tell angular to how to use these route config inside the application in orders to do so we have to pass the APP_ROUTER_PROVIDERS to our nativeScriptBootstrap method.

main.ts

import { nativeScriptBootstrap } from "nativescript-angular/application";
import { AppComponent } from "./app.component";
import { HTTP_PROVIDERS } from "@angular/http";
import { SIDEDRAWER_PROVIDERS } from "nativescript-telerik-ui/sidedrawer/angular";
import { APP_ROUTER_PROVIDERS } from "./router/router";

nativeScriptBootstrap(AppComponent, [
  HTTP_PROVIDERS,
  SIDEDRAWER_PROVIDERS,
  APP_ROUTER_PROVIDERS
]);

When we go to a specific path we want to load a view in a specific place. Where?

In order to tell angular where to load the view, we will use <router-outlet></router-outlet> directive.

app.component.html

<ActionBar title="GitUsers">
  <NavigationButton
    icon="res://ic_drawer"
    text="Go Back"
    (tap)="openDrawer()"
  ></NavigationButton>
</ActionBar>
<RadSideDrawer #drawer>
  <template drawerSide>
    <StackLayout class="p bgc-white">
      <ListView [items]="pages" row="1">
        <template let-item="item" let-i="index">
          <StackLayout>
            <label
              text="{{item.name}}"
              class="page-name"
              [nsRouterLink]="[item.path]"
            ></label>
          </StackLayout>
        </template>
      </ListView>
    </StackLayout>
  </template>
  <template drawerMain>
    <StackLayout class="m">
      <router-outlet></router-outlet>
    </StackLayout>
  </template>
</RadSideDrawer>

In above code on which menu item click which Component view to load can be done by using nsRouterLink directive

Pages

In app.component.html we are using <ListView> with passing pages as items. We have to update our pages array as

this.pages = [
  { name: "Home", path: "/list" },
  { name: "About", path: "/about" }
];

Also when you click menu item at the side draw we would want to close slide draw and show only the content. But by defult it won’t happen. We have to look for the route change event and close the the Side Draw when ever the route is changed.

// on every route change close the sideDrawer
this.router.events.subscribe(event => {
  this.drawer.closeDrawer();
});

The final app.component.ts will be.

import { Component, ViewChild, ChangeDetectorRef, OnInit } from "@angular/core";
import {
  RadSideDrawerComponent,
  SideDrawerType
} from "nativescript-telerik-ui/sidedrawer/angular";
import { userListComponent } from "./components/list/list.component";
import { ROUTER_DIRECTIVES, Router } from "@angular/router";
import { NS_ROUTER_DIRECTIVES } from "nativescript-angular/router";

@Component({
  selector: "my-app",
  directives: [userListComponent, ROUTER_DIRECTIVES, NS_ROUTER_DIRECTIVES],
  templateUrl: "app.component.html"
})
export class AppComponent implements OnInit {
  @ViewChild(RadSideDrawerComponent)
  public drawerComponent: RadSideDrawerComponent;
  private drawer: SideDrawerType;
  public pages: Array<Object>;

  constructor(
    private router: Router,
    private _changeDetectionRef: ChangeDetectorRef
  ) {
    this.router = router;
  }

  // on component init
  ngOnInit() {
    // List all pages and there router path here
    this.pages = [
      { name: "Home", path: "/list" },
      { name: "About", path: "/about" }
    ];

    // on every route change close the sideDrawer
    this.router.events.subscribe(event => {
      this.drawer.closeDrawer();
    });
  }

  // After veiw init
  ngAfterViewInit() {
    this.drawer = this.drawerComponent.sideDrawer;
    this._changeDetectionRef.detectChanges();
  }

  // on menu icon click
  public openDrawer() {
    this.drawer.toggleDrawerState();
  }
}

That’s it we are done. Now you have application with side drawer menu navigation.

Well done!!!