1
votes

I'm trying to set up an app with the following configuration:

~ There are two base pages controlled by authorization

  • Login Page - If no session-id
  • Dashboard Page - If logged in

~ Once on the Dashboard page I want to use this as a sort of container for other views. The dashboard is basically just a template with a navigation bar and router-view. I want the router view to be able switch between 2 pages/views while keeping the dashboard/navigation in place as the layout. The two pages are to switch between

  • Update-Feed
  • Test-Page

Here are the files as I currently have them set up

app.ts

import {NavigationInstruction, Next, Redirect, Router, RouterConfiguration} from 'aurelia-router';

/**
 * Main application router, controls views by authorization
 */
export class App {

  public router: any;

  public configureRouter(config: RouterConfiguration, router: Router): void {
    config.title = 'Dashboard';
    config.addPipelineStep('authorize', AuthorizeStep);

    // These are the two main routes a login page and a dashboard. 
    // Which page is visible is controlled by the authorization step
    config.map([
      {route: ['', 'pmdash'], name: 'pmdash', moduleId: './pages/pmdash/pmdash', nav: true,  auth: true},
      {route: 'login',        name: 'login',  moduleId: './pages/login/login',   nav: false, auth: false, title: 'Login'}
    ]);
    this.router = router;
    console.log(this.router);
  }
}

export class AuthorizeStep {

  // Method may be used elsewhere to verify user is logged in
  public static isLoggedIn(): boolean {
    let sessionID = sessionStorage.getItem('sessionID');
    return (typeof sessionID !== 'undefined' && sessionID !== null);
  }

  public run(navigationInstruction: NavigationInstruction, next: Next): Promise<any> {

    if (navigationInstruction.getAllInstructions().some(i => i.config.auth)) {
      let isLoggedIn = AuthorizeStep.isLoggedIn();

      if (!isLoggedIn) {
        return next.cancel(new Redirect('login'));
      }
    }
    return next();
  }
}

app.ts controls whether you land on a login page or the dashboard based on a session-id. This works, however once landing on the dashboard page it starts getting messed up... Here's the dashboard and corresponding navbar files

pmdash.html

<!-- Base template for PM Dashboard views -->

<template>

  <require from="../../components/navbar/navbar"></require>
  <nav-bar></nav-bar>
  <router-view></router-view>

</template>

pmdash.ts

import {Router, RouterConfiguration} from 'aurelia-router';

/**
 * Child router for Dashboard pages/views
 */
export class DashBoard {

  public router: Router;

  // On immediate navigation to the dashboard this loads `update-feed`, which works
  // However it only works because it is assigned the base route ''.
  // If I try to navigate to `update-feed` or `test-page` by url I get `Error: Route not found:` in console 
  public configureRouter(config: RouterConfiguration, router: Router) {
    config.map([
      {route: ['', 'update-feed'], name: 'update-feed', moduleId: './pages/update-feed/update-feed', nav: true, title: 'Feed'},
      {route: ['test-page'],       name: 'test-page',   moduleId: './pages/test-page/test-page',     nav: true, title: 'Test'}
    ]);
    this.router = router;

    // These console logs show the router is the child of `AppRouter` and has all the routes assigned to it, like it should.
    console.log(this.router);
    console.log(this.router.routes);
  }

}

navbar.html

<template>

  <nav class="navbar navbar-default navbar-fixed-top" role="navigation">

    <!-- Here is an effort to bind the router to the navigation -->
    <div class="navbar-header" router.bind="router">

      <!-- Here again clicking on the link gives `Route not found: /update-feed`-->
      <a class="navbar-brand" route-href="route: update-feed">
        <i class="fa fa-user"></i>
        <span>PM Dashboard</span>
      </a>

      <!-- This works. It calls the logout function which then redirects to the login page on the main router-->
      <button type="button" class="btn btn-default navbar-btn pull-right" click.delegate="logOut()">Log Out</button>
    </div>
  </nav>

</template>

navbar.ts Right now navbar.ts only contains the logOut() function so I'm skipping the code for brevity.

Now here are the two pages that I want the pmdash.ts child router to control. Basically the way I have it set up I would expect that when landing on the pmdash page/route then the pmdash view/viewmodel should handle these pages/views while staying in pmdash as sort of a template with the navbar on top, then depending on links (or default) switching out which view is displayed below the navbar.

update-feed.html

<template>

  <h1>You currently have no projects needing updated.</h1>

  <!-- Clicking this link gives `Error: Route not found: /test-page` in console-->
  <a route-href="route: test-page">click for test page</a>

</template>

test-page.html

<template>
  TESTING
  <!-- Clicking this link gives `Error: Route not found: /update-feed` -->
  <a route-href="route: update-feed">click for route page</a>
</template>

update-feed.html and test-page.html both have associated .ts files as well but for now they are blank.

I just do not understand what I am doing wrong. Am I misunderstanding how the router/child-routers handle pages on a fundamental level? Is there any way to make the configuration work like I currently have it, or do I need to scrap this approach and try something completely different?

Again, the main issue is that pmdash child-router will not switch views with the update-feed and test-page routes. However, if I assign either of the routes as route: '' then it will load fine, but I still can never link to the other route/view.

1
If you have answered your own question, please add and accept and answer - rather than edit your original post.Tom
I left it open since this "answer" is more of a workaround/hack. I will editDjH

1 Answers

4
votes

Ok, so I've "fixed" this, here's how:

At first I didn't really think that [this SO question][1] was relevant to my situation, but it was.

Basically the issue is with handling absolute routes and the base route (ie route: '') not being handled correctly when passing off routing to a child router.

The workaround is to make the parent router redirect like so (using my own app.ts from above as example):

  public configureRouter(config: RouterConfiguration, router: Router): void {
    config.title = 'Dashboard';
    config.addPipelineStep('authorize', AuthorizeStep);
    config.map([
      {route: '',      redirect: 'dashboard'},
      {route: 'dashboard', name: 'pmdash', moduleId: './pages/pmdash/pmdash', nav: true,  auth: true},
      {route: 'login',     name: 'login',  moduleId: './pages/login/login',   nav: false, auth: false, title: 'Login'}
    ]);
    this.router = router;
    console.log(this.router);
  }

This is apparently a workaround to a known issue with how the router handles an array of routes with a child router. However, although the workaround does work, console is now spitting this warning, Warning: a promise was rejected with a non-error: [object Object] at _buildNavigationPlan.... whenever the app root route is hit. This warning does not seem to have manifested itself into any actual issues yet...

what a headache