Understanding Ionic 2: Navigation with NavController

posted in: Uncategorized | 1

In Understanding Ionic 2: @Page, we learned how to create views using the @Page decorator and attach a template to the class. In this article we’ll learn about navigating between these pages using NavController and the navigation stack.

Ionic 1.0 Equivalent

In 1.0, there was the concept of states and a router. This was fairly simple and easy to use for simple apps but very quickly became a complicated mess when there were abstract states and nested states involved. There were situations where you had to completely rework your app to get the desired navigation and functionality.

In 2.0, we instead use the idea of a navigation stack.

Navigation Stack

A navigation stack is exactly what it sounds like, a stack of navigation. Each item in the stack is a previous view you have been on. Think of it like your browser history: each time you visit a page, a new page gets added to your history list. When you hit the back button, you go to the previous item in your history.

Ionic’s navigation stack is stored in and controlled by the NavController class. By injecting this class into a @Page, you can manipulate the navigation stack. Adding items to the stack uses a push method and removing items from a stack uses a pop method, very similar to an array in javascript.

To navigate from one view to another, we push a new page onto the navigation stack. To go back a page, we pop the view off the top of the stack. Instances of a @Page are created when they are added to the navigation stack. When a @Page is added to the navigation stack, the NavController compiles it and animates it into view.

navigation stack

Basic Push Usage

Before we can use the NavController, we will need to import it.

import {Page, NavController} from 'ionic-angular';

Next we will inject it into our @Page and assign it to a property.

import {Page, NavController} from 'ionic-angular';

@Page({
	templateUrl: "build/pages/Main/Main.html"
})
export class MainPage(){
	constructor(nav: NavController){
		this.nav = nav;
	}
}

Now, we can call properties on nav, our instance of NavController. For example, say we want to navigate from our Main view to our About view, we would need to start by importing that @Page class.

import {Page, NavController} from 'ionic-angular';
import {AboutPage} from 'About/About'

@Page({
	templateUrl: "build/pages/Main/Main.html"
})
export class MainPage(){
	constructor(nav: NavController){
		this.nav = nav;
	}
}

Next, let’s create a method on our page called goToAbout that we can call from our template. This method will push the AboutPage onto the stack.

import {Page, NavController} from 'ionic-angular';
import {AboutPage} from 'About/About'

@Page({
	templateUrl: "build/pages/Main/Main.html"
})
export class MainPage(){
	constructor(nav: NavController){
		this.nav = nav;
	}
	
	goToAbout(){
		this.nav.push(AboutPage);
	}
}

In our template, Main.html, we will have a button that will call this method when pressed.

<button (click)="goToAbout()">About</button>

To summarize, when this button is pressed, it will call the goToAbout method which pushes an instance of the AboutPage class onto the navigation stack which is then compiled and animated into view.

Passing Data

In many scenarios we have data in one view that we need to pass to another. Luckily, the push method accepts a second parameter which is an object of data to pass to the @Page passed into the first parameter.

this.nav.push(AboutPage,{
	username: "andrewmcgivery",
	blogger: true
});

This data is then accessible in the pushed @Page via navParams which is similar to $stateParams in 1.0.

import {Page, NavParams} from 'ionic-angular';

@Page({
	templateUrl: 'build/pages/About/About.html',
})
export class AboutPage {
	constructor(navParams: NavParams){
		this.username = navParams.get("username"); // "andrewmcgivery"
		this.blogger = navParams.get("blogger"); // true
	}
}

Pop

Pop is super simple to use as well. As an example, if we wanted to create a function called goBack that goes back when pressed in our AboutPage, we could just call nav.pop():

import {Page, NavController} from 'ionic-angular';

@Page({
	templateUrl: 'build/pages/About/About.html',
})
export class AboutPage {
	constructor(nav: NavController){
		this.nav = nav;
	}
	
	goBack(){
		this.nav.pop();
	}
}

Other Methods

There is a few more methods available on the NavController such as insert, remove, etc. I would suggest reading the Official Docs.

Lifecycle Events

In version 1.0, we had the concept of events being fired when we were entering and leaving the view, among others. In version 2.0, we have a very similar set of events. To handle one of these events, we just need to give our @Page class a method that matches the event. For example, if we want to run an event when the @Page is loaded, we will need to give our page the onPageLoaded method:

import {Page} from 'ionic-angular';

@Page({
	templateUrl: 'build/pages/About/About.html',
})
export class AboutPage {
	onPageLoaded(){
		console.log("Page Loaded!");
	}
}

We can have a set of handlers for a variety of events including then the page is about to be entered, when the page is leaving, etc. Again, I would suggest reading the Official Docs.

Example: Master Detail

As covered in my version 1 tutorials Ionic: Master Detail Pattern and Hello Master Detail: Your Fourth Ionic Framework App, the master detail pattern is a very common pattern in computer software where you have a master list of data and when an item from that list is selected, the user is presented with details about that item.

In Ionic 2.0, thanks to the ability to pass data between views, this becomes very easy to accomplish. As an example, lets create a MasterPage and a DetailsPage. The MasterPage will contain a list of people. When one of these list items is selected, the MasterPage will push the DetailsPage onto the navigation stack, passing the details of the list item that was selected.

Let’s start with our MasterPage class. For our example, we will have a hard-coded array of objects called people. We will also have a goToDetails method that pushes the DetailsPage class onto the navigation stack and passes along a person object.

import {Page, NavController} from 'ionic-angular';
import {DetailsPage} from 'Details/Details'

@Page({
	templateUrl: 'build/pages/Master/Master.html',
})
export class MasterPage {
	constructor(nav: NavController){
		this.nav = nav;
		
		//Hard-coded for Example
		this.people = [
			{
				firstName: 'Andrew',
				lastName: 'McGivery',
				bio: "Developer @manulife | Jack of Many Trades | I blog about @ionicframework";
			},
			{
				firstName: 'Brandy',
				lastName: 'Carney',
				bio: "SDK Developer at Ionic - @ionicframework. Developed @appcampio. ❤️ wine and animals.";
			},
			{
				firstName: 'Mike',
				lastName: 'Hartington ',
				bio: "Ionic Developer Advocate. I trick people into thinking I can do code. GDE";
			}
		]
	}
	
	goToDetails(person){
		this.nav.push(DetailsPage, person);
	}
}

For our Master.html template, we will list through the people array and for each item we will display a list item with the person’s first name and last name. When the list item is pressed, it will call our goToDetails method and pass the current person object from our ngFor.

<ul>
	<li *ngFor="#person of people" (click)="goToDetails(person)">
		{{person.firstName}} {{person.lastName}}
	</li>
</ul>

In our DetailsPage, we will get the entire person object using navParams.data:

import {Page, NavParams} from 'ionic-angular';

@Page({
	templateUrl: 'build/pages/Details/Details.html',
})
export class DetailsPage {
	constructor(navParams: NavParams){
		this.person = navParams.data; //Gets the person object
	}
}

… and in the template we will display the first name, last name, and bio:

<h1>{{person.firstName}} {{person.lastName}}</h1>
<p>{{person.bio}}</p>

… and just like that, we have accomplished the master detail pattern!

Mobile Development for Web Developers

NavPush and NavPop

If you prefer to navigate between each @Page with a more familiar, declarative syntax similar to what you might do in V1 with ui-sref, you can use NavPush to pass in an instance of a page.

import {LoginPage} from 'login';
@Page({
  template: `<button [navPush]="pushPage"></button>`
})
class MyPage {
  constructor(){
    this.pushPage = LoginPage;
  }
}

See the official documentation (NavPush, NavPop) for more details.

Conclusion

While there are a number of options to the new navigation stack and it is in many ways a very different system from 1.0, the push/pop system makes many things simpler when creating an app. It allows for a lot of flexibility in the flow of our app and lots of control on a page by page basis. Questions? Leave them below!

Special Thanks

Huge thanks to Brandy Carney for reviewing/editing this post!

NOTE: Beta

Please be aware that Ionic 2 is in beta and is subject to change at any time. If this post becomes inaccurate at any time, feel free to leave a comment and I’ll do my best to update it as soon as I can.

My name is Andrew McGivery. I currently work full time as an application developer at Manulife Financial in Canada.

One Response

  1. Great article Andrew. I think the nav stack navigation is probably the best of many great changes between Ionic and Ionic 2.

Leave a Reply