Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Navigation trade off #12402

Closed
AmitMY opened this issue Jul 18, 2017 · 13 comments
Closed

Navigation trade off #12402

AmitMY opened this issue Jul 18, 2017 · 13 comments

Comments

@AmitMY
Copy link
Contributor

AmitMY commented Jul 18, 2017

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

I'm submitting a ... (check one with "x")
[ ] bug report
[x] 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:
Having an app with navigation guards (ionViewCanEnter), and URL segments, does not allow a fallback for page evaluation.

Having an app with authentication, lets say I have 3 pages:

page/link guard
login isGuest : Promise
home isAuthenticated: Promise
other isAuthenticated: Promise

If I don't set rootPage, nothing happens by default, so I have to set it, and the only choice is login

Now if I go to /home, I see a blank page, because it tried to load the home page, but the user is not authenticated. User must go to either / or /login.

After the user is authenticated, now when he goes to /home, everything is fine, but if by accident he pressed on a link of /login, there is a blank page (can't enter, so nothing)

Finally, one would say: Check if the user is authenticated. if they are, set rootPage to home, and if not to login.

But what if the user (authenticated) goes to /other? they are immediately redirected to home. A possible suggestion would be to check the active page, but because of the nav guard, there is no active page before we know if the user is authenticated, so must also add a timeout for it to happen asyncronically.

Note: this does not happen only with authentication, even with sequential nav guards, like checking if page got all parameters.

Expected behavior:
I think there should be an option to bind a function to the nav, like onCantEnter or something, that fires only if the first page it tries to load can not be entered. It would get the component it tried to load, and let the user do whatever with that information, for example:

this.nav.onCantEnter((page) => {
  if(UNAUTHENTICATED_PAGES.indexOf(page.name) > -1)
    this.nav.setRoot('HomePage');
  else 
    this.nav.setRoot('LoginPage')
});

Note: I din't find where in the code it does that first load and executes ionViewCanEnter, so I can't create a PR.

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

global packages:

    @ionic/cli-utils : 1.5.0
    Cordova CLI      : 7.0.1
    Ionic CLI        : 3.5.0

local packages:

    @ionic/app-scripts              : 2.0.2
    @ionic/cli-plugin-cordova       : 1.4.1
    @ionic/cli-plugin-ionic-angular : 1.3.2
    Cordova Platforms               : browser 4.1.0
    Ionic Framework                 : ionic-angular 3.5.2

System:

    Node       : v8.1.2
    OS         : Windows 10
    Xcode      : not installed
    ios-deploy : not installed
    ios-sim    : not installed
    npm        : 5.0.3 
@danbucholtz danbucholtz self-assigned this Jul 18, 2017
@ey-aroberts
Copy link

@AmitMY
Curious if your issue is the same one we faced?

We wrap ion-nav in a <div *ngIf="!hideHomePage">

We do not set the rootPage until we verify if the user is logged in or not. If logged in we set the rootPage to their homepage and set hideHomePage = false. This means that the logic to render the page is not called until we know the state of the user.

@AmitMY
Copy link
Contributor Author

AmitMY commented Jul 18, 2017

Not sure what issue you faced, as you come on empty when I filter issues

I did the same idea, setting rootPage to null, and updating only when I know the state, but it does not work well with dynamic links, like in the example above /other.

It is quite similar to #11459

@ey-aroberts
Copy link

Is this a website or a mobile app?

My current app works as such. Are you trying to do something similar?

Logged in user
www.test.com/my-account/pay-bill -> If user token, log user in, go to page.
www.test.com -> If user token, log user in, go to dashboard which is /my-account

Non Logged in user
www.test.com/my-account/pay-bill -> If no user token, go to Generic Login. Once logged in go to pay-bill

www.test.com -> if no user token stay on page.

CSR view
If csr.test.com -> redirect user to csr page

@AmitMY
Copy link
Contributor Author

AmitMY commented Jul 18, 2017

Both.
So you check for the entering page, cool. What method are you using to get that info?

@ey-aroberts
Copy link

ey-aroberts commented Jul 18, 2017

I have an auth class as follows

export abstract class Auth {

  isAccountServiceReady: boolean = false;


  constructor(public navCtrl: NavController, public navUtil: NavUtility, public loginService: LoginService, public userService: UserService, public _logger: Logger, public accountListService: AccountListService) {
    this.accountListService.accountReadyEmitter.subscribe((user: User) => {
      this.isAccountServiceReady = true;
    });
  }

  ionViewCanEnter(): boolean | Promise<any> {
    if (!this.userService.isLoggedIn() && !this.userService.isLoggingIn) {
      if (this.navUtil.moveToPage) {
        this.loginService.genericLoginModalRedirectionName = this.navUtil.moveToPage;
      } else {
        this.loginService.genericLoginModalRedirectionName = this.loginService._location.path();
      }
      this.navUtil.navigate(this.navCtrl, 'GenericLoginPageComponent', true);
    }
    else
      return true;
  }

  ionViewDidEnter() {
    if (this.userService.user.currentAccount != undefined) {
      this.isAccountServiceReady = true;
    }
  }


}

@AmitMY
Copy link
Contributor Author

AmitMY commented Jul 18, 2017

The interesting part here for me is NavUtility. Mind sharing that? I am interested to know how you find moveToPage

@ey-aroberts
Copy link

ey-aroberts commented Jul 18, 2017

I have a whole lot of custom logic to manage navigation between pages atm.

I have a custom directive that allows navigation. As well as logic to use the serializer to get the component the current page is on. The I have the ability to setRoot and handle failures in that utility. At the moment it has error cases custom for our app that handles some odd cases due to the serializer. Let me see if I can get a slimmed down version for you.

I also have analytics tracking in the utility.

@ey-aroberts
Copy link

I guess what you care about is this line

      this.moveToPage = segments[0].name;
      return nav.setRoot(segments[0].name, Object.assign({}, segments[0].data, moveToPageParam), navOptions)
        .then(res => {
          this.moveToPage = null;
        })

If there is an issue navigating to a page we set the after generic login page as the last page we tried to navigate to. Else we set it to null so that we set the last page as the current page we are on per the browser.

@mburger81
Copy link
Contributor

Hi, this is exactly my opinion.
I and some others tried already to figure out this design patterns and we opened some issues and feature requests like #12193 and #11459

@ztecharoberts solutions is nice, and something we already tried or at least something similar. But there is something I'm not sure about:
On ionViewCanEnter you never return false when user is not logged in and you redirect to Page with this.navUtil.navigate. What is happening in this case?? Is the page accessing or not?
In our case the page was accessing and then redirect to new page. In this case it depends which is faster, if the redirect page is fast you don't see open the page, if not you firstly see the page and will then be redirected to new page. Perhaps you don't will see it because you are working if ngIf?

I think implementing a classical solution of Guards with the possibility to have multiple states and redirect user, would much more power, is much more readable code and more flexible.

In the past, redirecting roots on guards was available but removed on 3.5.x. So the rooter how is it know (working good) with the ability to redirect pages would be most of the things we all need.

The good news are, Dan wrote to work on it soon, I hope we can test and give feedback in a few days.

Thx to all

@ey-aroberts
Copy link

ey-aroberts commented Jul 19, 2017

@mburger81

all of our pages show a loading spinner until accounts are ready.

        <div *ngIf='isAccountServiceReady==true'>
            <component [accountNumber]='accountNumber'></component>
        </div>
        <div *ngIf='isAccountServiceReady==false'>
            <loading></loading>
        </div>

@mburger81
Copy link
Contributor

Okay, but there are could be code in IonDidEnter and others, so there should also be no code in it. Right?

@ey-aroberts
Copy link

The idea is our pages contain little to no code in them. We have a lot of our logic based in components. If the component is not rendered none of our code is executed.

@ionitron-bot
Copy link

ionitron-bot bot commented Jul 19, 2018

Thanks for the issue! This issue is being closed due to inactivity. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.

Thank you for using Ionic!

@ionitron-bot ionitron-bot bot closed this as completed Jul 19, 2018
@ionitron-bot ionitron-bot bot locked and limited conversation to collaborators Jul 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants