ionic-framework: Navigation freezes sometimes when using the ionViewCanEnter hook

Ionic version: (check one with “x”) (For Ionic 1.x issues, please use https://github.com/ionic-team/ionic-v1) [ ] 2.x [ x] 3.x [ ] 4.x

I’m submitting a … (check one with “x”) [ x] bug report [ ] feature request

Current behavior: When using the hook “ionViewCanEnter” and returning a promise, the navigation can freeze sometimes when a back navigation is performed. In that case, it is not possible to navigate back or forward. I suppose that there is a timing problem when the promise takes too long? This bug cannot be reproduced in every case. Unfortunately it occurs often enough to be considered a blocker in our productive app.

By some debugging I could see the following: When the naviagtion is stuck for the first time, the promise returned by method _transitionStart in NavControllerBase is never fulfilled. The call “transition.onFinish(resolve)” does not call the given resolve callback.

Expected behavior: The navigation should work, no matter how long the promise returned by ionViewCanEnter needs to fulfill.

Steps to reproduce:

  • checkout the github project (see below)
  • add the iOS platform
  • run the app on an iPad (my OS is iOS 11)
  • do this until the navigation freezes
    • use the button to go the next page
    • on the next page, hit the back button as fast and often as you can 😉

Related code: See https://github.com/chhe88/IonViewCanEnteExample The first page has an implementation of ionViewCanEnter which causes a delay of 5 secs.

Ionic info: (run ionic info from a terminal/cmd prompt and paste output below): cli packages: (/usr/local/lib/node_modules)

@ionic/cli-utils  : 1.12.0
ionic (Ionic CLI) : 3.12.0

global packages:

cordova (Cordova CLI) : 7.0.1 

local packages:

@ionic/app-scripts : 2.1.4
Cordova Platforms  : ios 4.4.0
Ionic Framework    : ionic-angular 3.6.1

System:

ios-deploy : 1.9.2 
ios-sim    : 6.0.0 
Node       : v7.8.0
npm        : 4.6.1 
OS         : macOS Sierra
Xcode      : Xcode 9.0 Build version 9A235 

Misc:

backend : legacy

screen shot 2017-09-26 at 09 27 30

screen shot 2017-09-26 at 09 27 40

Thanks in advance for your help! 😃

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 15 (8 by maintainers)

Most upvoted comments

Minor tweak to my workaround above after looking at the existing code more:

    this.navBar.backButtonClick = (e: UIEvent) => {
      if (!this.navigating) {
        this.navigating = true;
        e.preventDefault();   // added these two lines.
        e.stopPropagation();
        this.navCtrl.pop();
      }
    }

Sorry I didn’t had a look at your code, but do you redirect page in your guards or some functions called by the guards and reject the promise? For example check if user is still authenticated, if not redirect to login page and reject guard. Could this be?

Hello! Thank you for opening an issue with us!

I had time to take a quick look at this earlier. I noticed that in the browser, if I hit the back button more than once, it will toss an exception. The first click tries to go back, the second click causes the root page to go NULL and toss an error. Not ideal.

I’ll look at this later, but in the meantime, I will share the strategy I use in my own apps:

  1. I don’t like using promises in guards. I find it to be bad UX. Thus I only put stuff in functions like ionViewCanEnter that can be resolved synchronously and then return true or false. This is generally limited to checking a set of permissions or roles fetched on startup and/or login.
  2. I extend the Angular HTTP service like this to handle 401 errors coming back from my data service. In the linked case, which is from an Angular SPA and not an Ionic app, it redirects to the login page, but you can have it do whatever you need to do.
  3. In the page, rather than guarding against user not logged in, I assume they are logged in and attempt the main request for the page’s data. If that returns 401, the user gets redirected. This make the app far less chatty than a “am I logged in” request followed by an “OK then give me data” request.

Sorry that the linked example of an extended HTTP service was not for an Ionic app, but the ones I have written for Ionic apps were all for a former employer rather than my own project.

Another idea I have is to perhaps override the back button event controlling everything yourself so you can’t get multiple clicks while waiting. I have not had time to try that out yet. I may have time later today.

Hopefully, that can get you started thinking about things you can try, though.

Thank you for using Ionic