Ionic-framework: Navigating via url to a page where ionViewCanEnter() fails leads to a white screen

Created on 27 Apr 2017  路  15Comments  路  Source: ionic-team/ionic-framework

Ionic version: (check one with "x")

[ ] 1.x
[ ] 2.x
[x] 3.x

I'm submitting a ... (check one with "x")

[x] bug report
[ ] feature request
[ ] support request => Please do not submit support requests here, use one of these channels: https://forum.ionicframework.com/ or http://ionicworldwide.herokuapp.com/

Current behavior:

With the new lazy loading structure and the Deeplinking method, using NavGuards becomes even more important. But when I use IonViewCanEnter(), I can only return false or true and not set the new page to navigate to, if I load the page directly by URL, so the only thing I will be seeing is a blank screen. I have already tried to pass defaultHistory via @IonicPage(), but that is not working as well

Expected behavior:

I should have to able to set the page I would want to navigate to in case the ionViewCanEnter() fails when typing in the url.

Ionic info: (run ionic info from a terminal/cmd prompt and paste output below):

Cordova CLI: Not installed
Ionic Framework Version: 3.1.0
Ionic CLI Version: 2.2.3
Ionic App Lib Version: 2.2.1
Ionic App Scripts Version: 1.3.5
ios-deploy version: 1.9.1
ios-sim version: 5.0.13
OS: macOS Sierra
Node Version: v6.10.2
Xcode version: Xcode 8.3.1 Build version 8E1000a

v3

Most helpful comment

@rayhaanq I use something like this:

ionViewCanEnter(): boolean {
  if (isAuthorized) {
    return true;
  } else {
    setTimeout(() => this.navCtrl.setRoot('LoginPage'), 0);
    // displayError();
    return false;
  }
}

You can also move this code to a service if most of your nav guards have the same behaviour (e.g., checking if the user is logged in).
All you need to do then is move the above code in a method of your service, and then in your component add the following:

ionViewCanEnter(): boolean {
  return this.authService.securePageCanEnter();
}

All 15 comments

You can, because you can navigate to new page by doing something like that

import { App, ToastController } from 'ionic-angular';
constructor(private appCtr: App) {}

and in the guard you do something like that
this.appCtr.getRootNav().setRoot('BlackPage');

First of all, I'm not sure if this should be the right implementation of doing this, I asked it several times on forum and github but I never got a response to it. So this for now is for me the only one solution I know.
Pay attention on endless loops!

And for second, FIY there are many many many bugs and problems with LazyLoading NavController and NavGuards and others.

Read this bug #11374 and my last to comments from today there.
If you can help us, we are happy to have any help!!

It does work! I have already had similar situations where we currently have to use appCtrl.getRootNav().setRoot() instead of navCtrl.setRoot(), is this actually the way it should work or why does it work like this?

Are you asking if this is by design??
Or are you asking we you have to use appCrt instead of navCtr?

I'm asking whether it is by design, don't understand the difference and when to use which one.

I don't know if it is by design.
I never got a response on how we have to handle this, and I never see an example of this implementation nor it is documented.
So perhaps you are a luckier guy then me.

Why using appCrt instead of navCtr? In our case we have a multi level of navigation. NavCtrl always returns the nearest by the page, so if you are on a SUB SUB SUB SUB page/navigation you are not sure which one you will get back and if it is the right one.
In our case on NavGuards we always will load the BLACKPAGE on THE first navigation component which is always and from everywhere the appcCtr.getRootNav().
At least this is what we think, we never get an answer about that. So we are really not sure but we have no other solution under the hand.

Hello @MvRemmerden , could you create a minimal repo that we can use to take a look at this issue? Thanks!

Sure, will do so tonight.

Another workaround is using setTimeout

setTimeout(function() {
  navCtrl.setRoot('login');
}, 0);

is there any update on this? How would a typical ionViewCanEnter guard look using this timeout workaround?

@rayhaanq I use something like this:

ionViewCanEnter(): boolean {
  if (isAuthorized) {
    return true;
  } else {
    setTimeout(() => this.navCtrl.setRoot('LoginPage'), 0);
    // displayError();
    return false;
  }
}

You can also move this code to a service if most of your nav guards have the same behaviour (e.g., checking if the user is logged in).
All you need to do then is move the above code in a method of your service, and then in your component add the following:

ionViewCanEnter(): boolean {
  return this.authService.securePageCanEnter();
}

Hi, can somebody explain how the setTimeout workaround works? 馃

Thanks in advance

@rricamar there's an example in my latest comment, just before yours.
The trick is to wrap the redirection in a setTimeout with a time set to 0 (to actually not add any delay), and return the boolean expected by the method immediately.
It allows for the redirection to be executed after the return statement, and thus not block the validation process.
Not sure why this is needed, but it does work, that's all that matters to me !

timeout will be making the navigation asynchronous, return will complete separately to the application navigating to the other page.

This issue has been automatically identified as an Ionic 3 issue. We recently moved Ionic 3 to its own repository. I am moving this issue to the repository for Ionic 3. Please track this issue over there.

If I've made a mistake, and if this issue is still relevant to Ionic 4, please let the Ionic Framework team know!

Thank you for using Ionic!

Was this page helpful?
0 / 5 - 0 ratings