1
votes

I'm building angular2 app and currently I have an home component with menubar and router-outlet for the main content. I have added the login mechanism, so if the user is not authenticated then the login page will be displayed in the entire screen and after login the user will be routed to the main/home component with the structure above.

When i run the application the login page loads, and on successfully authenticated, it routes me to the home page, but in the home page where the menus are loaded (like Dashboard1, Dashboard2, Report1, etc), the links are not working properly. I am getting the below mentioned error when I click on any menubar links.

    lib/@angular/platform-browser/bundles/platform-browser.umd.js:1900 Error: Uncaught (in promise): Error: Cannot match any routes: 'Report1'
        at resolvePromise (zone.js:538)
        at zone.js:515
        at ZoneDelegate.invoke (zone.js:323)
        at Object.onInvoke (lib/@angular/core/bundles/core.umd.js:9100)
        at ZoneDelegate.invoke (zone.js:322)
        at Zone.run (zone.js:216)
        at zone.js:571
        at ZoneDelegate.invokeTask (zone.js:356)
        at Object.onInvokeTask (lib/@angular/core/bundles/core.umd.js:9091)
        at ZoneDelegate.invokeTask (zone.js:355)

I have the router-outlet tag in 2 places i.e. 1 in the AppLoader and also in the LayoutMenu component where the actual menus are being loaded and it contains the router-outlet to load the main content there.

what is the correct place to have the router-outlet ? where I am doing the mistake?

the following is the code for routeconfig

export const routes: RouterConfig = [
    { path: '', component: Login },
    { path: 'login', component: Login },
    { path: 'Home', component: Home },
    { path: '**', component: Login }
];
export const LOGIN_ROUTER_PROVIDERS = [
    provideRouter(routes)
];

Home/Menu routeconfig is as below

export const routes: RouterConfig = [
    {
        path: 'home',
        component: Home,
        // canActivate: [AuthenticationGuard],
        children: [

            { path: 'Dashboard1', component: Dashboard1 },
            { path: 'Dashboard2', component: Dashboard2 },
            { path: 'Report1', component: Report1 },
            { path: 'Report2', component: Report1 },

            {
                path: 'ManageRedisCache',
                component: ManageRedisCache,
                children: [
                    { path: '', component: ExtractorQueue },
                    { path: 'Extractor', component: Extractor },
                    { path: 'Schedule', component: Schedule },
                    { path: 'CacheVisualization', component: CacheVisualization }
                ]
            }
        ]
    }
];

export const HOME_ROUTER_PROVIDERS = [
    provideRouter(routes)
];

The above 2 routeconfig are injected via the main.ts bootstrap. In the main.ts bootstrap I also inject AppLoader which contains the .

AppLoader component is as below which contains/loads the login page.

@Component({
    selector: 'my-app',
    template: `<router-outlet></router-outlet>`,
    directives: [Login, ROUTER_DIRECTIVES ]
})
export class AppLoader {
}

LayoutMenu component is as below:

import { Component } from '@angular/core';
import { ROUTER_DIRECTIVES } from '@angular/router';
@Component({
    selector: 'MenuLayout',
    template: `
        <a [routerLink]="['/Dashboard1']"><h4>Dashboards 1</h4></a>
        <a [routerLink]="['/Dashboard2']"><h4>Dashboards 2</h4></a>
        <a [routerLink]="['/Report1']"><h4>Reports 1</h4></a>
        <div class="outer-outlet">
        <router-outlet></router-outlet>
        </div>  `,
    directives: [LeftMenu, ROUTER_DIRECTIVES]
})
export class LayoutMenu { }
1

1 Answers

4
votes

Angular router is flexible enough that you can achieve the same results having different configurations. Bellow is one possible example.

You want two different base templates:

  1. Login template
  2. Content template (left menu / right workspace)

A sample main app.component routes config:

export const routes: RouterConfig =
[
    ...ContentRoutes,
    {
        path: 'login',
        component: LoginComponent
    },
{
        path: '',
        redirectTo: '/home',
        pathMatch: 'full'
    },
    {
        path: '**',
        redirectTo: '/404',
        pathMatch: 'full'
    }
];

Now on to content.component routes (pages with left menu / right workspace):

export const ContentRoutes: RouterConfig = [
    {
        path: 'home',
        component: ContentComponent,
        canActivate: [AuthenticationGuard],
        children: [
            {
                path: '',
                component: MainHomeComponent,
                canActivate: [AuthenticationGuard]
            }
        ]
    },
    {
        path: '404',
        component: ContentComponent,
        canActivate: [AuthenticationGuard],
        children: [
            {
                path: '',
                component: PageNotFoundComponent,
                canActivate: [AuthenticationGuard]
            },
        ]
    },
    {
        path: '500',
        component: ContentComponent,
        canActivate: [AuthenticationGuard],
        children: [
            {
                path: '',
                component: PageErrorComponent,
                canActivate: [AuthenticationGuard]
            },
        ]
    },
];

All content.component routes should pass through an AuthenticationGuard before routing, thats why the canActivate property. More on angular router docs.

I've also added 404/500 route examples.


On to the templates. Base app.component template will only have a RouterOutlet:

<router-outlet></router-outlet>

It should route to either login.component or content.component (depending on user authentication).

content.component is your "left menu and workspace" template, so it should have both base layout components and a RouterOutlet:

<div id="wrapper">
    <div id="page-wrapper" class="gray-bg">
        <div class="left-menu">
            <app-menu></app-menu>
        </div>
        <router-outlet></router-outlet>
        <app-footer></app-footer>
    </div>
</div>

(sample html)

Recap:

Base path ('/') will redirect to '/home' which defaults to MainHomeComponent having ContentComponent as a parent. Freely add more children routes to it.

Sample project on github.