Populating a child router-outlet Angular2

Craig O. Curtis picture Craig O. Curtis · Mar 5, 2017 · Viewed 7.6k times · Source

Since I heard Angular's Router supports nested <router-outlet> tags, I'm trying to use two of them. I"m using the latest Angular-CLI, converting from ui-router to Angular's Router. I can't get the second router-outlet to populate content.

(The parent routing is working fine) app-routing.module.ts

...
const routes: Routes = [
    { path: '', pathMatch: 'full', component: LoginComponent },
    { path: 'login', pathMatch: 'full', component: LoginComponent },
    { path: 'dashboard',
        pathMatch: 'full',
        component: DashboardComponent // this holds the second router-outlet
    },
    { path: '**', component: LoginComponent }
];

@NgModule({
    imports: [
        RouterModule.forRoot(routes)
    ],
    exports: [ RouterModule ]
})
export class AppRoutingModule { }

app.component.ts -- this just holds the router-outlet, and works fine at the top level...

<router-outlet></router-outlet>

The dashboard holds universal headers, footers, sidebars, etc. So that's why I want it in the top-level router-outlet. The sub-router-outlet will populate child views, but doesn't populate.

Attempt 1 dashboard-routing.module.ts

export const dashboardRoutes: Routes = [
    { path: '', pathMatch: 'full', redirectTo: 'home' },
    { path: 'home', pathMatch: 'full', component: HomeComponent },
    { path: 'about', pathMatch: 'full', component: AboutComponent }
]
@NgModule({
    imports: [
        RouterModule.forChild(dashboardRoutes)
    ],
    exports: [ RouterModule ]
})
export class DashboardRoutingModule { }

Attempt 2 dashboard-routing.module.ts as per Angular2 : Multiple Router-Outlets & Router-Outlets Inside Child Route

export const dashboardRoutes: Routes = [
    {
        path: 'dashboard',
        children:[
            { path: '', component: DashboardComponent},
            { path: 'home', component: HomeComponent},
            { path: 'about', component: AboutComponent}
        ]
    }
 ]
@NgModule({
    imports: [
        RouterModule.forChild(dashboardRoutes)
    ],
    exports: [ RouterModule ]
})
export class DashboardRoutingModule { }

Inside the Dashboard template, this nested router-outlet does not populate. Instead, the top-level router-outlet in the app.component.html is populated instead :(

dashboard.component.html

<header>...</header>
<aside class="sidenav">...<aside>

<!-- why can't I populate you? -->
<router-outlet></router-outlet>

************** Answer, a great thank you to PierreDuc! **************

app-routing.module.ts

// seems counter-intuitive that the dashboard component isn't actually in here..., but it works!
const routes: Routes = [
    { path: '', pathMatch: 'full', component: LoginComponent },
    { path: 'login', pathMatch: 'full', component: LoginComponent },
    { path: '**', component: LoginComponent }
];
@NgModule({
    imports: [
        RouterModule.forRoot(routes),
        DashboardRoutingModule // this is the magic. I'm assuming to put it second is better (though putting it first didn't seem to have any immediate negative effect)
    ],
    exports: [ RouterModule ]
})
export class AppRoutingModule { }

dashboard-routing.module.ts

export const dashboardRoutes: Routes = [
    {
        path: 'dashboard',
        component: DashboardComponent,
        children:[
            { path: '', component: HomeComponent },
            { path: 'home', pathMatch: 'full', component: HomeComponent },
            { path: 'about', pathMatch: 'full', component: AboutComponent }
        ]
    }
]
@NgModule({
    imports: [
        RouterModule.forChild(dashboardRoutes)
    ],
    exports: [ RouterModule ]
})
export class DashboardRoutingModule { }

Here's how to navigate from the root:

login.component.ts

... passed validation ...
this._router.navigate(['/dashboard']);
this._router.navigate(['/dashboard/home']);

or routing via routerLink via a sidebar in the Dashboard dashboard.component.html

[routerLink]="['../login']" <!-- back to login, though the '../' seems less than ideal

or in the dashboard view via routerLink to child router-outlets: dashboard.component.html:

[routerLink]="['../about']"

Answer

Poul Kruijt picture Poul Kruijt · Mar 5, 2017

Child router-outlets are populated with the children array inside the router configuration. But there's duplication going on. You should remove the dashboard entry inside your AppRoutingModule, and go for attempt 2:

app-routes

const routes: Routes = [
    { path: '', pathMatch: 'full', component: LoginComponent },
    { path: 'login', pathMatch: 'full', component: LoginComponent },
    { path: '**', component: LoginComponent }
];

And keep your DashboardRoutingModule as is it is in attempt 2 (with the children array), and import this module either inside the AppRoutingModule, or in the AppModule.