Greg Gum
Greg Gum

Reputation: 37905

Screen Freezing when Setting Multiple Roots

When my aurelia app starts I send them first to the login page and check and see if they are logged in and if so, set set the root to app, otherwise, have them log in.

 aurelia.start().then(() => aurelia.setRoot(PLATFORM.moduleName("modules/login")));

This should work, according to everything I could find. It does actually set the root to as far as the code is concerned as I see activity in the console, but the html on the screen never moves from the login screen. Even typing something manually in the address bar does not change the html. So it seems the router has stopped functioning. No errors are logged in the console.

import { AuthenticateStep, AuthService } from 'aurelia-authentication';
import { Router} from 'aurelia-router';
import { autoinject, PLATFORM, Aurelia } from "aurelia-framework";

@autoinject()
export class Login {

    constructor(private router: Router, private authService: AuthService, private aurelia:Aurelia) {
            console.log("Starting Login...")
    }

    activate() {
        if (this.authService.authenticated) {
            console.log("is authenticate")
            this.router.navigate('/', { replace: true, trigger: false });

            console.log("setting root to 'app'");
            this.aurelia.setRoot(PLATFORM.moduleName("app"));


        }
        else {
            console.log("not auth");
        }
    }
}

In app.ts

activate() {
  console.log("app.activate");
  ...

}

This is the console

Is there something else I should be doing?

I have tried: https://github.com/aurelia/framework/issues/400

And this: https://ilikekillnerds.com/2017/07/aurelia-routing-switching-root-using-setroot/

Upvotes: 0

Views: 189

Answers (2)

Fred Kleuver
Fred Kleuver

Reputation: 8047

Here are a few things you can try:

  • Chain the promises (make sure the navigation is done before you tell aurelia to switch the root)

    this.router.navigate('/', { replace: true, trigger: false })
        then(() => this.aurelia.setRoot(PLATFORM.moduleName("app")));
    
  • Resolve the promises (would be necessary if the router still has work to do after the current activate because that work would need to be aborted)

    return this.router.navigate('/', { replace: true, trigger: false })
        then(() => this.aurelia.setRoot(PLATFORM.moduleName("app")));
    
  • Verify that the AppRouter is reconfigured after you switch root (breakpoint in configureRouter, you may need to manually .reset() the router is the isConfigured flag is somehow still true)

You could try a different approach altogether.

Personally when I need to switch root between a public and an authenticated shell, I just have a dedicated path prefix for either (or both) and in my main method I set the root to the correct App based on the current window.location.

Example (in main):

if (/\/public/.test(window.location.pathname)) {
  au.setRoot(PLATFORM.moduleName("shell/public"));
} else if ((/\/admin/.test(window.location.pathname)) {
  au.setRoot(PLATFORM.moduleName("shell/admin"));
} else {
  au.setRoot(PLATFORM.moduleName("shell/app"));
}

Redirecting between these roots goes outside of the router, simply with window.location.href = "...";

Although it's arguably a little hacky, the nice thing about the approach is that you'll always have a completely clean Aurelia state after switching, and thus less you potentially need to clean up after.

In the non-public roots, you try to grab the auth token from localStorage and simply kick the user back to public if there is none (or they don't have sufficient privileges).

Upvotes: 1

Greg Gum
Greg Gum

Reputation: 37905

Setting the root is quite easy, but there is a caveat:

Set it either in response to a user generated event, or in the attached event.

Attempting to set it in the activated event or constructor will result in the screen becoming frozen on the root screen.

This took me pretty much a day to figure out, so I thought I would pass it on.

Here is what worked for me: I created a "app-shell" which is set to the root by main.

In app-shell, I check whether or not the person is already logged in, and then I set the root depending on the results.

import { AuthenticateStep, AuthService } from 'aurelia-authentication';
import { AppRouter } from 'aurelia-router';
import { autoinject, PLATFORM, Aurelia } from "aurelia-framework";

@autoinject()
export class AppShell {

    constructor(private router: AppRouter, private authService: AuthService, private aurelia: Aurelia) {

    }

    attached() {
        this.setRoot();
    }

    setRoot() {
        this.router.navigate('/', { replace: true, trigger: false }); //Not actually needed here, but is if the router has already been configured.
        if (this.authService.authenticated) {
            this.aurelia.setRoot(PLATFORM.moduleName("app"));
        }
        else {
            this.aurelia.setRoot(PLATFORM.moduleName("modules/login"));
        }


    }
}

Upvotes: 0

Related Questions