ionViewCanEnter still executing page load

I have a common set of code that runs on ionViewCanEnter, which checks if a user is logged in before displaying secure pages. This seems to work…on the surface.

When a user isn’t logged in, there is a split second where the page is seen before it navigates to the non-authenticated page. I can also see that the page load does get executed (ionViewDidEnter does fire). The page access is blocked…eventually. How can I prevent the page load from executing, and prevent the page from being displayed for a split second? Here’s my common implementation of ionViewCanEnter.

ionViewCanEnter() {
    this.loggingService.debug("securePage: ionViewCanEnter");
    this.auth.hasLoggedIn().then((loggedIn) => {
        if (!loggedIn) {
            this.loggingService.error("Blocked a page view - user not logged in");
            this.events.publish(Constants.EVENT_LOGOUT, true);
            return false;
        }

        //Good to go
        return true;
    }).catch((error) => {
            this.loggingService.error("Secure Page: error getting loggedin status: " ,error);
            this.events.publish(Constants.EVENT_LOGOUT, true);
            return false;
        }
    );
}

Please post ionic info.

Can do!

global packages:

    @ionic/cli-utils : 1.4.0
    Cordova CLI      : 6.5.0
    Ionic CLI        : 3.4.0

local packages:

    @ionic/app-scripts              : 1.3.7
    @ionic/cli-plugin-cordova       : 1.4.0
    @ionic/cli-plugin-ionic-angular : 1.3.1
    Cordova Platforms               : android 6.1.2 browser 4.1.0 ios 4.3.1
    Ionic Framework                 : ionic-angular 3.4.2-201706201953

System:

    Node       : v6.10.2
    OS         : Windows 10
    Xcode      : not installed
    ios-deploy : not installed
    ios-sim    : not installed
    npm        : 4.5.0

The guards got some fixes in 3.5.1 so you might upgrade to that and see if it changes.

Also, isn’t your catch in the wrong place? That might be the issue, that you’re forcing the page to catch the error. Pretty sure you’re supposed to place the catch on the original push command in the previous page.

1 Like

Thanks! I’ll wait until the release notes come out on that one and give an upgrade a try.

Also, isn’t your catch in the wrong place? That might be the issue, that you’re forcing the page to catch the error. Pretty sure you’re supposed to place the catch on the original push command in the previous page.

I’m no JS expert, but the intent on that catch was to handle any error that may have resulted from the call to this.auth.hasLoggedIn(). If it can’t determine if the user is logged in or not, it should assume the user is not logged in (hence returning false there).

So you’re running an asynchronous call inside the guard? Why not set up the auth provider so that it returns a boolean when you query if someone is logged in? Presumably the provider already knows if it’s handling log-ins and log-outs. I wouldn’t place any interesting logic in a guard, myself – just true or false, the end, for fastest-possible resolution. That’s an intuition that might be wrong, or might be “right” but still not affect this issue, I don’t know. But if I were facing this problem, it’s the first thing I’d change.

Yes, it does depend on an async call. The logic to determine if a user is logged in for my case depends on storage, which introduces promises to make sure storage is ready and to get data out of the storage. It should be quick, but it does depend on promises.

I don’t see how this should matter. The method shouldn’t return until it gets the data, so whether it does a bunch of processing within the method or via a promise, it shouldn’t matter.

I do see these guards seem to be able to return boolean/Promise<void>. I figured boolean was easier but I suppose I could adjust this to return a promise.

@AaronSterling - you pointed me in the right direction, thanks! While the method I had was returning a bool inside the promise.then, the function overall couldn’t be considered as a return type of boolean. This guard was executed, and I was navigating away from the page in the guard logic which made it SEEM like the guard was partially working. Ultimately it was never truly blocking the page access because I wasn’t truly returning a boolean though.

Since I rely on promises here, changing my implementation to return a promise worked well.

2 Likes

@brassier So what did you end up doing? You code looked like how? I describe mine here, yet still face the same issue:

Because if I do this, it still flashes unwanted content:

  ionViewCanEnter() {
    if(!this.auth.isLoggedIn()) {
      this.navCtrl.setRoot(WelcomePage);
      return true;
    }
  }

thanks

@seanmavley - My guess is your method isn’t a valid return type of boolean. I bet if you change your method signature to ionViewCanEnter() : boolean it may not be valid typescript? This is because you’re not returning false as a default case. I’d try that first. If that fails then you could adjust to use promises. Just resolve the promise if the user is logged in, or reject it if it isn’t. I did get my guards to function properly by using promises.

This may get rid of your FOUC, but you’re still going to run into problems here. The Ionic guards don’t do well with navigation from within the guard (your setRoot(WelcomePage). I’ve resolved to not using guards for my project.