98

I'm looking for a solution with Angular 2 for the scenario explained below:

enter image description here

In this scenario, the top-nav contains links to load submodules and sub-nav has links to update the submodule's contents.

The URLs should map as:

  • /home => loads the home page in main component router outlet
  • /submodule => loads the submodule in the main component router outlet and by default should show the submodule's home page and sub navbar
  • /submodule/feature => loads the feature inside the submodule's router outlet

The app module (and app component) contains a top navbar to navigate to different submodules and the app component template could look like this

<top-navbar></top-navbar>
<router-outlet></router-outlet>

But here is the complexity. I need my submodules to have a similar layout with a second level nav bar and their own router outlet to load their own components.

<sub-navbar></sub-navbar>
<router-outlet name='sub'></router-outlet>

I tried every option and search everywhere but couldn't find a solution to have a default template (like app component) in the sub-module with router outlet and also load the contents of submodule in the inner router outlet without losing the sub-nav.

I would appreciate any input or ideas

Josef
  • 2,869
  • 2
  • 22
  • 23
Ron F
  • 1,021
  • 1
  • 8
  • 4
  • So what exactly is happening with the current setup? – micronyks Jan 25 '17 at 17:30
  • 1
    with the current setup I cannot use inner router outlet. The routing loads even submodule components in the main router outlet and all my submodule component templates have to have a the sub-nav included – Ron F Jan 25 '17 at 17:49
  • 1
    did you find a solution to nested router-outlet without loosing the sub-navigation? I have landed into a similar issue. – Saurav Jul 14 '17 at 02:49
  • 2
    Yea i think i ran into the same, the just doesn't display, only whats coming out of the routeroutlet. – louisvno Jan 25 '18 at 12:19

4 Answers4

66

The html page will look like this.

Main Page

<top-navbar></top-navbar>
<router-outlet></router-outlet>

Sub Module Page

<sub-navbar></sub-navbar>
<router-outlet name='sub'></router-outlet>

on clicking navigation in top-nav bar the main route outlet will route respectively.

while clicking on sub-navbar the router-outlet [sub] will route respectively.

HTML is fine, the trick will came at writing app.routing

app.routing.ts

const appRoutes: Routes = [
  {
    path: 'login',
    component: LoginComponent
  },
  { path: 'home',
    component: homeComponent,
    children: [
      {
        path: 'module1',
        component: module1Component,
        children: [
          {
            path: 'submodule11',
            component: submodule11Component,
          },
          {
            path: '',
            redirectTo: 'submodule11',
            pathMatch: 'full'
          }
        ]
      },
      {
        path: 'module2',
        component: module2omponent,
        children: [
          {
            path: 'submodule21',
            component: submodule21Component,
          },
          {
            path: '',
            redirectTo: 'submodule21',
            pathMatch: 'full'
          }
        ]
      }
    ]
  },
  {
    path: 'about',
    component: aboutComponent
  }
]

Hope it will help you.

More details https://angular.io/guide/router

Josef
  • 2,869
  • 2
  • 22
  • 23
Aswin KV
  • 1,710
  • 2
  • 12
  • 23
  • 1
    Yesh your html str was correct, The main game is with app.routing.ts I had done similar applications two times. – Aswin KV Jan 25 '17 at 19:20
  • 2
    Thanks for the answer. I tried the similar routing but my confusion is where should that submodule router outlet go? on the main module it is clear that the router outlet should be in app.component's template but we don't have same concept of app component for submodules. so where the "sub" router outlet goes? – Ron F Jan 25 '17 at 20:31
  • Also how should the routerLink in the sub-navbar look like ? – Ron F Jan 25 '17 at 21:00
  • 3
    The router link must be a string if you add '/' in the beginning of the string it will replace the current route if you dont add '/' the route link will add withe the current route. Still you are not clear please create an sample application in some online coding platform and share the link – Aswin KV Jan 26 '17 at 05:33
  • 3
    I'm not completely sure about this, but the nested `router-outlet` directive does not need to be named. Here is an example: https://github.com/gothinkster/angular-realworld-example-app/blob/63f5cd879b5e1519abfb8307727c37ff7b890d92/src/app/profile/profile.component.html – Jess Aug 29 '18 at 20:12
  • 1
    actually it seems that the nested `router-outlet`MUST NOT be named. It works for me only if I do not name it. – stefan.m Jan 05 '21 at 14:33
  • 1
    @stefan.m Thank you. I removed the name and it started to work! – AmirHossein Rezaei Jan 29 '23 at 21:22
28

Use:

RouterModule.forChild()
...
<router-outlet name="sub"></router-outlet>
...
[routerLink]="[{ outlets: { sub: [subRouteName] } }]"

Full example:

HTML

<div class="tabs tinyscroll">
  <button *ngFor="let tab of tabs"
  [routerLink]="[{ outlets: { sub: [tab.name] } }]"
  routerLinkActive="selected">
    <span>{{ tab.label }}</span>
  </button>
</div>

<section>
  <router-outlet name="sub"></router-outlet>
</section>

app.module.ts

imports: [
...
    RouterModule.forChild([
      {
        path: 'registers',
        component: RegistersComponent,
        children: [
          {path: 'vehicles', component: VehiclesComponent, outlet: 'sub'},
          {path: 'drivers', component: DriversComponent, outlet: 'sub'},
          {path: 'bases', component: BasesComponent, outlet: 'sub'},
          {path: 'lines', component: LinesComponent, outlet: 'sub'},
          {path: 'users', component: UsersComponent, outlet: 'sub'},
          {path: 'config', component: ConfigComponent, outlet: 'sub'},
          {path: 'companies', component: CompaniesComponent, outlet: 'sub'}
        ],
        canActivate: [AuthGuard]
      }
    ]),
...
Martin Schneider
  • 14,263
  • 7
  • 55
  • 58
thxmxx
  • 447
  • 4
  • 9
2

you have to mention the outlet name in the routes mention your router outlet name in the routing like this "outlet:'sub"

routes: Routes = [
  {path:'', redirectTo: 'login', pathMatch: 'full'},
  {
    path: 'login',
    component: LoginComponent,

  },
  { path: 'home',
    component: AppComponent,
      children: [
        {path: 'home/pdf',component: SideMenuPage,outlet:"sub" },
        {path:'home/addFileUp',component:SidePageAdd,outlet:"sub"},
      ]
   },
];
Muhammed Yusuf
  • 146
  • 2
  • 20
Nambi N Rajan
  • 491
  • 5
  • 15
  • this snippet returns an error: "Uncaught ReferenceError: LoginComponent is not defined" – Umpa Jan 11 '19 at 11:52
-2

This would work In Your Template.

<h2>First Component</h2>

<nav>
  <ul>
    <li><a routerLink="child-a">Child A</a></li>
    <li><a routerLink="child-b">Child B</a></li>
  </ul>
</nav>

<router-outlet></router-outlet>

In AppRoutingModule.

const routes: Routes = [
  {
    path: 'first-component',
    component: FirstComponent, // this is the component with the <router-outlet> in the template
    children: [
      {
        path: 'child-a', // child route path
        component: ChildAComponent, // child route component that the router renders
      },
      {
        path: 'child-b',
        component: ChildBComponent, // another child route component that the router renders
      },
    ],
  },
];

Read more from https://angular.io/guide/router#nesting-routes