简体   繁体   中英

Ionic 3. No provider for NavController

My question is similar to the one found here

But i'm not sure if its the same scenario for him, since the error goes away sometimes when I stop the app and restart using ionic serve. The error returns back again randomly. I have noticed that when I use debugger statement in the app.component.ts constructor I can bypass the error. Any help would be appreciated. Thank you.

Here is my code

app.component.ts

export class MyApp {
    @ViewChild('content') nav: Nav;

    rootPage: any = HomePage;

    pages: Array<{ title: string, component: any }>;


    constructor(public platform: Platform,
    public statusBar: StatusBar,
    public splashScreen: SplashScreen) {
    this.initializeApp();

    this.pages = [
      { title: 'Dashboard', component: DashboardPage },
    ];
    debugger
  }

  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.
      this.statusBar.styleDefault();
      this.splashScreen.hide();
    });
  }

  openPage(page) {
    // Reset the content nav to have just this page
    // we wouldn't want the back button to show in this scenario
    this.nav.setRoot(page.component);
  }
}

app.html

<ion-menu [content]="content">
  <ion-header>
    <ion-toolbar>
      <ion-title>Menu</ion-title>
    </ion-toolbar>
  </ion-header>

  <ion-content>
    <ion-list>
      <button menuClose ion-item *ngFor="let p of pages" (click)="openPage(p)">
        {{p.title}}
      </button>
    </ion-list>
  </ion-content>

</ion-menu>
<ion-nav #content swipeBackEnabled="false" [root]="rootPage"></ion-nav>

home.ts

export class HomePage {
  token: string;
  constructor(public navCtrl: NavController,
    public menuCtrl: MenuController,
    public storage: Storage) {
    setTimeout(() => {
      this.storage.get('_token').then((token) => {
        this.token = token;
        if (this.token && this.token.length > 0) {
          this.navCtrl.setRoot(DashboardPage)
        } else {
          this.navCtrl.setRoot(LoginPage)
        }
      }).catch((error) => {
        console.log(error);
        this.navCtrl.setRoot(LoginPage)
      });
    }, 1000)
  }

  ionViewWillEnter() {
    this.menuCtrl.enable(false);
  }
  ionViewWillLeave() {
    this.menuCtrl.enable(true);
  }

}

login.ts

export class LoginPage {
  username: string;
  password: string;

  constructor(public navCtrl: NavController,
    public navParams: NavParams,
    public userProvider: UserProvider,
    public storage: Storage,
    public alertCtrl: AlertController,
    public menuCtrl: MenuController) {

  }

  ionViewDidLoad() {
    console.log('ionViewDidLoad LoginPage');
  }

  login() {
    console.log("Logging in...", this.username, this.password);
    var credentials = { 'email': this.username, 'password': this.password };
    this.userProvider.login(credentials).then((validResponse: any) => {
      console.log('success', validResponse);
      var data = validResponse.data;
      this.storage.set('_token', data.token);
      this.navCtrl.setRoot(DashboardPage);
    }).catch((errorResponse: any) => {
      console.log('error', errorResponse);
      var title = '';
      var subTitle = '';
      title = "Oops!"
      if (errorResponse.status == 401) {
        subTitle = "Invalid Username/Password";
      } else {
        var errorObject = errorResponse.error;
        if (errorObject.errors) {
          for (let error of errorObject.errors) {
            subTitle += error + '. ';
          }
        } else {
          subTitle = errorResponse.message;
        }
      }
      this.presentAlert(title, subTitle);
    });
  }

  presentAlert(title, subTitle) {
    let alert = this.alertCtrl.create({
      title: title,
      subTitle: subTitle,
      buttons: ['Ok']
    });
    alert.present();
  }

  ionViewWillEnter() {
    this.menuCtrl.enable(false);
  }
  ionViewWillLeave() {
    this.menuCtrl.enable(true);
  }

}

login.html

<ion-content padding>
  <div class="login-holder">
    <ion-img class="logo" width="120" src="../../assets/imgs/logo.png"></ion-img>
    <br>
    <ion-img class="hero" width="250" src="../../assets/imgs/restaurant.png"></ion-img>
    <ion-input class="username" [(ngModel)]="username" type="text" placeholder="Phone or Email"></ion-input>
    <ion-input class="password" [(ngModel)]="password" type="password" placeholder="Password"></ion-input>
    <button class="login" ion-button full (click)="login()">Login</button>
  </div>
</ion-content>

My flow is like this, HomePage is a temporary screen before going to login page, after a timeout I take to LoginPage or Dashboard Page, depending on if they already have a token in local storage. From Login page, I take the users to Dashboard Page.

Since I'm new to angular and ionic, I'm not even sure if I'm doing it right. I have looked into all the similar questions in stack overflow.

  • Most of them got solutions by having passing App module in the constructor and retrieving navcontroller from the app. But that didnt work for me.
  • Some suggested to check on the import path so I cross verified with docs & starter project it seems correct.
  • Some suggested to remove passing nav controller in the constructor but if you check my code I havent passed in constructor in app.component.ts I have only passed in the page's constructors which is in the skeleton code generated by the ionic generate page command.

Thanks again for the time.

Change your Home.ts to:

export class HomePage {
  token: string;
  constructor(public navCtrl: NavController,
    public menuCtrl: MenuController,
    public storage: Storage) {

  }

  ionViewWillEnter() {
    this.menuCtrl.enable(false);
  }
  ionViewWillLeave() {
    this.menuCtrl.enable(true);
  }

  ionViewDidLoad() {
    setTimeout(() => {
      this.storage.get('_token').then((token) => {
        this.token = token;
        if (this.token && this.token.length > 0) {
          this.navCtrl.setRoot(DashboardPage)
        } else {
          this.navCtrl.setRoot(LoginPage)
        }
      }).catch((error) => {
        console.log(error);
        this.navCtrl.setRoot(LoginPage)
      });
    }, 1000)
  }

}

After looking around for a while. I found the problem. I was missing @IonicPage decorator in my home.ts. It got resolved after adding it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM