Aurelia Routing + Switching Root Using setRoot

Last updated: July 10, 2017

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.

Purchase Aurelia for Real World Applications over at Leanpub now

 

Dwayne

 

Leave a Reply

Your email address will not be published. Required fields are marked *