ionViewCanEnter on ion-tabs

Hi All. Running into a problem hoping someone else has solved, looked everywhere and nobody has said anything about it. Seems like there is possibly an omission on the way ion-tabs works. When transitioning from a login page that has no tabs, to a tabs page - containing a home page that requires a ionViewCanEnter promise to be completed - the ion-tabs doesn’t wait for the promise of the home page even though it is the default (selected index) tab. So what happens is you get a flash of white (or whatever nav-decor is) while the home page resolves it’s CanEnter. Here is a simple dumbed-down example:

pages/login.ts

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { TabsPage } from './tabs';

@Component({
  selector: 'page-login',
  template: '<ion-content style="background-color: #00f"><button (click)="login()">Login</button></ion-content>'
})
export class LoginPage {

  constructor(public navCtrl: NavController) {}

  login() {

    this.navCtrl.push(TabsPage);
  }
}

pages/tabs.ts

import { Component } from '@angular/core';
import { HomePage } from './home';

@Component({
  template: '<ion-tabs selectedIndex="0"><ion-tab [root]="homeRoot" tabTitle="Home" tabIcon="home"></ion-tab></ion-tabs>'
})
export class TabsPage {

  homeRoot: any = HomePage;

  constructor() { }

  ionViewCanEnter() {
    // Wishing this would wait for HomePage's ionViewCanEnter
  }
}

pages/home.ts

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

@Component({
  selector: 'page-home',
  template: '<ion-content style="background-color: #0f0">Welcome Back!</ion-content>'
})
export class HomePage {

  constructor() { }

  ionViewCanEnter() {

    // imagine we are doing http stuff that takes 5 seconds...

    return new Promise(function(resolve, reject) {

      setTimeout(resolve, 5000);
    });
  }
}

How can I make it so TabsPage.ionViewCanEnter waits for the HomePage.ionViewCanEnter? Any ideas would be greatly appreciated. Would be great if it were not a hack, lol. Seems like Ionic should handle this automatically. I tried making TabsPage.ionViewCanEnter = homeRoot.ionViewCanEnter but it didn’t do anything.

In ionic1, we had something like Controller(HomePage, function() { … }).factory(function(Http) { return { Http.get(…) } }); on the HomePage, which resolved all the http requests before displaying itself, and there was no flash between login and tabs/home…

Thanks!

If you don’t get any better answers, what I would do is just let the home page go ahead and activate when it wants to, and when it’s ready to enter, use LoadingController to fire up a spinner while you are busy doing whatever needs to be done in the background.

Thanks. Yeah I have a hack right now where the default tab is a hidden tab with a loading page that then immediately navigates to the home page. But really it should just be instant because the http promises on the home page take almost no time to resolve… so it ends up being a blink blink to from login to home, doesn’t feel native, feels like a website…

I have one more idea: move the Http stuff out of HomePage and into a service. Expose a Promise<void> that resolves when it’s done in that service. Inject said service in TabsPage and return that promise from the ionViewCanEnter hook. I don’t know what your logic looks like for firing off the Http stuff, but whereever it is should be able to also inject that same service and get things going. I hope this makes some sense.

That would work but :cry: the code would be so ugly.

I guess that’s somewhere reasonable people can disagree on opinions, but I really like having all of my backend interaction out of components and in services. I feel like it’s a clean division of labor, and I find it often makes further modifications to things considerably easier.

Sorry I didn’t mean it that way. There are 2 services being called on the HomePage, it’s not a raw http call. The actual code looks like this:

  ionViewCanEnter() {

    var p = [];

    var user_o = this.userSvc.get();
    user_o.subscribe(data => this.user.next(data), err => {});
    p.push(user_o.toPromise());

    var favs_o = this.favoritesSvc.all();
    favs_o.subscribe(data => this.favorites.next(data), err => {});
    p.push(favs_o.toPromise());

    return Promise.all(p);
  }

this.favorites and this.user are BehaviorSubjects.

I could move that code to the TabsPage controller and pass the result to the HomePage, but then the logic for getting content for the Home screen is not in the HomePage controller, which would be inconsistent with the rest of the app pages/tabs/etc, which get their content from their own component.

:+1:

Solution for now is to have the default tab be an interim page with html that is exactly the same as the login page, and has a setRoot in it’s constructor that changes to the home page.

The result is that basically it looks like the tabs appear on top of the login page and then the login page visually switches directly to the home page.