In your Aurelia applications, you might have two or more roots defining different entry points into your application. I personally create a public facing root which has public routes and an auth protected shell which has routes for logged in users only.
Let’s say for this example you have two roots: publicRoot and privateRoot. Your publicRoot view-model has your login/logout and other public routes, and your privateRoot view-model has routes for an administration panel.
Upon successful login, you might want to redirect the user to their administration panel. Switching the root to our private one and having a default route as our admin panel will do the trick. But there is a problem.
If your URL is: http://localhost:9000/#/auth/login
and you switch the root, you’ll get an error in the console about your auth/login
route not being found. This is because you just switched the root view-model and your auth/login
route no longer exists.
The solution is to redirect to the base of your application and rewrite the browser history stack, before changing the shell:
this.router.navigate('/', { replace: true, trigger: false });
aurelia.setRoot(PLATFORM.moduleName('privateRoot'));
The options provided to navigate
are quite important. We are rewriting the browsers URL history by supplying replace: true
and trigger: false
allowing us to switch roots without encountering route issues as a result of the current route no longer existing.
This is fine and dandy if you’re changing the root from within an app view-model, but in my case I also want to check within my main.ts
file where I bootstrap the app to see if the user is already logged in.
This is where you’ll need to leverage the DI container Aurelia provides to get an instance of the router and then use its navigate method.
import {Container} from 'aurelia-framework';
import {Router} from 'aurelia-router';
export async function configure(aurelia: Aurelia) {
aurelia.use
.standardConfiguration()
.developmentLogging()
.feature(PLATFORM.moduleName('resources/index'))
await aurelia.start();
await aurelia.setRoot(PLATFORM.moduleName('publicRoot'));
firebase.auth().onAuthStateChanged(user => {
if (user) {
const router = Container.instance.get(Router);
router.navigate('/', { replace: true, trigger: false });
aurelia.setRoot(PLATFORM.moduleName('privateRoot'));
}
});
}
In my example I am using Firebase, but you could use anything. Pay close attention to the router and navigate method, followed by the setRoot
call setting our root to the admin view-model if we’re logged in.
Conclusion
As always, there might be edge cases I haven’t encountered and downsides to the above approach. Always test code snippets you find online, but the above works fine for me and will most likely work well for you too.
Hey, extending your answer for Aurelians who use Aurelia-Auth: https://stackoverflow.com/questions/50088169/screen-freezing-when-setting-multiple-roots/50091354#50091354