Aurelia - Switching between app roots with differe

2019-06-18 04:52发布

问题:

UPDATE

Could this issue have something to do with mu problem? https://github.com/aurelia/framework/issues/400


I have an Aurelia application with two different roots, one for loggen in users, and another for anonymous users.

I have in other Aurelia apps implemented a chanaging of app root based on the approach in this answer. This works very well when the login module is an "isolated" module with no additional routes, but I'm having a hard time getting it to work now.

index.js - root for anonymous users

import {inject, useView, Aurelia} from "aurelia-framework";
import AuthService from "./services/auth-service";

@useView("app.html")
@inject(AuthService)
export class Index {   
    constructor(authService) {
        this.auth = authService;
    }

    configureRouter(config, router) {
        config.title = "Super Secret Project";
        config.options.pushState = true;
        config.map([
            { route: ["","home"], moduleId: "home", nav: true, title: "Beginscherm" },
            { route: "over", moduleId: "about", nav: true, title: "Over" },
            { route: "inloggen", moduleId: "account/login", nav: false, title: "Inloggen" }
        ]);

        this.router = router;        
    }
}

ic-app.js - root for logged in users

import {useView, inject} from "aurelia-framework";
import {RequestStatusService} from "./services/request-status-service";
import AuthService from "./services/auth-service";

@useView("app.html")
@inject(RequestStatusService, AuthService)
export class App {
    constructor(requestStatusService, authService) {
        this.requestStatusService = requestStatusService;
        this.auth = authService; // we use it to bind it to the nav-bar-top
    }

    configureRouter(config, router) {
        config.title = "Super Secret Project";
        config.options.pushState = true;
        config.map([
            { route: ["", "selecteer-school"], moduleId: "ic/select-school", nav: false, title: "Selecteer School" },
            { route: "dashboard", moduleId: "ic/dashboard", nav: true, title: "Beginscherm" },
        ]);

        this.router = router;
    }
}

login code on auth-service.js

logIn(userData, rememberMe = false) {
    this.requestStatusService.isRequesting = true;
    return this.http
        .fetch("/token", { method: "POST", body: userData })
        .then((response) => response.json())
        .then(response => {
            if (response.access_token) {
                this.setAccessToken(response.access_token, response.userName, rememberMe);
                this.app.setRoot("ic-app");
            }
        });
}

and...

log off code in auth-service.js

logOff() {
    AuthService.clearAccessToken();
    this.app.setRoot("index");
}

The Problem

Setting the different app roots works as expected, the problem is that I would expect the new app root to automatically navigate to the default route of the new root, bit it tries to load the route it was on the moment setRoot(...) is called.

To illustrate with an example,

  1. I'm on the login page. current route: /inloggen
  2. I click the log in button. app.setRoot("ic-app") is called
  3. New root is loaded; configureRouter in ic-app.js is called, and then...
  4. Console error: Route not found: /inloggen

The new root tries to stay in the same /inloggen route, but I would like it to load, or navigate to, the default route for that app root. The same happens on logging out.

How can I force the app to navigate to the default route after changing root?

回答1:

I got this working great, I answered more about how to in this stackoverflow thread:

Aurelia clear route history when switching to other app using setRoot

Basically do the following

this.router.navigate('/', { replace: true, trigger: false });
this.router.reset();
this.router.deactivate();

this.aurelia.setRoot('app');


回答2:

In the router for anonymous users use the mapUnknownRoutes. Like this:

configureRouter(config, router) {
    config.title = "Super Secret Project";
    config.options.pushState = true;
    config.map([
        { route: ["","home"], moduleId: "home", nav: true, title: "Beginscherm" },
        { route: "over", moduleId: "about", nav: true, title: "Over" },
        { route: "inloggen", moduleId: "account/login", nav: false, title: "Inloggen" }
    ]);

     config.mapUnknownRoutes(instruction => {
       //check instruction.fragment
       //return moduleId
       return 'account/login'; //or home
     });

    this.router = router;        
}

Do the same strategy in the other router. Now, try to logout and login again, you will see the user will be redirected to his last screen.

EDIT

Another solution is redirecting to desired route after setting the rootComponent. For instance:

logOut() {
   this.aurelia.setRoot('./app')
    .then((aurelia) => {
      aurelia.root.viewModel.router.navigateToRoute('login');
    }); 
}

Here is a running example https://gist.run/?id=323b64c7424f7bec9bda02fe2778f7fc



回答3:

My best practice would be to simply direct them there, and this is what I do in my applications:

login(username, password) {
  this.auth.login(username, password)
    .then(() => {
      this.aurelia.setRoot('app');
      location.hash = '#/';
    });
}