15
votes

i have a problem with my ionic 2/angular 2 app.

I got an app.ts where the hole "auth" part is implementet.

The code looks like this:

 import {Nav, Platform, Modal, ionicBootstrap} from "ionic-angular";
import {NavController} from "ionic-angular/index";
import {StatusBar} from "ionic-native";
import {Component, ViewChild} from "@angular/core";
import {AngularFire, FirebaseListObservable, FIREBASE_PROVIDERS, defaultFirebase} from "angularfire2";
import {HomePage} from "./pages/home/home";
import {AuthPage} from "./pages/auth/home/home";

@Component({
  templateUrl: "build/app.html",
})

class MyApp {
  @ViewChild(Nav) nav: Nav;

  authInfo: any;
  rootPage: any = HomePage;
  pages: Array<{title: string, component: any}>;

  constructor(private platform: Platform, private navCtrl: NavController, private af: AngularFire) {
    this.initializeApp();

    this.pages = [
      { title: "Home", component: HomePage }
    ];

  }

  initializeApp() {
    this.platform.ready().then(() => {
      // Okay, so the platform is ready and our plugins are available.
      // Here you can do any higher level native things you might need.
      StatusBar.styleDefault();
    });
  }

  openPage(page) {
    this.nav.setRoot(page.component);
  }

  ngOnInit() {
    this.af.auth.subscribe(data => {
      if (data) {
        this.authInfo = data;
      } else {
        this.authInfo = null;
        this.showLoginModal();
      }
    });
  }

  logout() {
    if (this.authInfo) {
      this.af.auth.logout();
      return;
    }
  }

  showLoginModal() {
    let loginPage = Modal.create(AuthPage);
    this.navCtrl.present(loginPage);
  }
}

But now, when i try to run the app i get this message:

ORIGINAL EXCEPTION: No provider for NavController

Do you have any idea how to solve this problem? Thanks!

7

7 Answers

20
votes

You can not inject a NavController in a Root component via a constructor.

So, basically you can not do something like below:-

constructor(private nav: NavController){
}

This is how you can inject a NavController

@Controller({
  ....
})
class MyApp{
  @ViewChild('nav') nav: NavController;
  ....
  ....
  constructor(...){ // See, no NavController here
  }
  ....
}

And this is what Ionic docs has to say.

What if you want to control navigation from your root app component? You can't inject NavController because any components that are navigation controllers are children of the root component so they aren't available to be injected.

By adding a reference variable to the ion-nav, you can use @ViewChild to get an instance of the Nav component, which is a navigation controller (it extends NavController)

15
votes

You can't inject the NavController in your Root Component so you should remove it from that part of the code. Further information can be found here.

Please make sure you already have a reference variable in your ion-nav, like this (the #myNav):

<ion-nav #myNav [root]="rootPage"></ion-nav>

And then you can get that reference by using ViewChild. You can then just navigate to another page, by using that property:

import { Nav, Platform, ... } from "ionic-angular";
// more imports...
// ...

@Component({
  templateUrl: "build/app.html"
})

class MyApp {
  @ViewChild('myNav') nav: NavController // <--- Reference to the Nav

  authInfo: any;
  rootPage: any = HomePage;
  pages: Array<{title: string, component: any}>;

  // Remove the "navCtrl: NavController" from the constructor, since
  // now your getting the reference from the view
  constructor(private platform: Platform, private af: AngularFire) {
    this.initializeApp();

    this.pages = [
      { title: "Home", component: HomePage }
    ];

  }

  // ...

  openPage(page) {
    // this.navCtrl.setRoot(page.component); <-- Wrong!
    this.nav.setRoot(page.component) // <-- Right! Use the this.nav property
  }

  // ...
}
8
votes

It's recommended you use this.app.getActiveNavs() in Ionic 3+ as getActiveNav() will be removed in the next major release, so your function can be written as:

showLoginModal() {
    let loginPage = Modal.create(AuthPage);
    this.getActiveNavs().slice(-1)[0].present(loginPage);
}

To push on the nav stack, you can just import the page (say YourPage) then:

this.getActiveNavs()[0].push(YourPage);

Old behaviour, for Ionic 2, deprecated in Ionic 3:

You can use this.getActiveNav() in Ionic 2 (and Ionic 3), so your function can be written as:

showLoginModal() {
    let loginPage = Modal.create(AuthPage);
    this.getActiveNav().present(loginPage);
}

With either method you don't need any import or private variable for this to work. If you're in a Component, just refer to your App:

import {App} from 'ionic-angular';
import {MyPage} from '../pages/my/page';

@Component()
export class MyComponent {
    constructor(private app: App) {
    }
    goToMyPage() {
        this.app.getActiveNav().push(MyPage);
    }
}
2
votes

Ok, i just used the nav instead of NavigationController and now it works.

2
votes

I handled it with:

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

constructor(protected app: App) {
... }

get navCtrl(): NavController {
    return this.app.getRootNav();
}

Answer taken from here: github issues

1
votes

You named your nav incorrectly;

this.nav.setRoot(page.component);

Should be

this.navCtrl.setRoot(page.component);

And double check if your importing correctly

import { NavController} from 'ionic-angular';
0
votes

One cause for this error is when you try to inject NavController into a provider class.
Like this:

@Injectable()
export class MyProviderService {

  constructor(private nav: NavController){
  }
}

I just had that error...
After removing this injection (and refactoring the code), it worked fine.