1
votes

I can't get Angular to route the following scenario involving nested router-outlets. The idea is to have an application-wide banner at the top, followed by a dashboard navigation component which has its own router-outlet to display components. Those components should be able to have their own router-outlets so that (for example, to display a master-detail pattern with master on left and detail on right). I'm able to route a single named outlet, but not a named child outlet within another named outlet.

AppComponent contains the primary outlet <router-outlet></router-outlet>, which is to display DashboardNavComponent from a lazy-loaded module. DashboardNavComponent contains <router-outlet name='dashboard'></router-outlet> which should display the main components. I can get that to work (i.e. routing to 'app/dashboard/user/1' displays the banner, navigation and UserMasterComponent. But I have been unable to route to app/dashboard/user/1/contact and show the banner, navigation, UserMasterComponent and also Contact component in the detail router-outlet.

These are simplified versions of my routes and I've tried multiple route configurations. I have been able to get it to work by breaking them out into separate 'user/:id/contact' and 'user/:id/profile' routes, but that causes the DashboardNavComponent and UserMasterComponent to reload on each route change between them. I'm fairly new to Angular, but if they are child routes of 'user/:id' I would assume that it only refreshes the component for final ActivatedRoute (i.e. 'contact' or 'profile').

app-routing.module.ts

const routes = {
  path: 'app',
  children: [
    {
      path: 'dashboard',
      loadChildren: () => import('./dashboard/dashboard.module').then(m => m.DashboardModule)
    }
  ]
}

dashboard-routing.module.ts

const routes = {
  {
    path: 'user/:id',
    component: DashboardNavComponent,
    children: [
      {
        path: 'contact',
        component: UserMasterComponent,
        outlet: 'master',
        children: [
          {
            path: '',
            component: ContactComponent,
            outlet: 'detail'
          }
        ]
      },
      {
        path: 'profile',
        component: UserMasterComponent,
        outlet: 'master',
        children: [
          {
            path: '',
            component: ProfileComponent,
            outlet: 'detail'
          }
        ]
      }
    ]
  }
};
1

1 Answers

3
votes

After spending over a full work-day on this the past few days, I solve it within 10 minutes of posting on Stack Overflow :) Hopefully this is helpful to someone as I did not find any issues that clearly documented this solution.

I was unaware that each feature could have one unnamed primary router-outlet and was thinking my entire application could have only one. The solution was to make the root router-outlet of the dashboard feature the primary router-outlet and only assign a name to one router-outlet, the 'detail' one. Then, in the route configuration, I removed any instances of outlet: 'dashboard'.

To prevent the DashboardNavComponent from reloading on each route change, I also had to nest all my Dashboard routes in a catch-all route.

Final dashboard-routing.module.ts

const routes = {
  {
    path: '',
    component: DashboardNavComponent, // Set component here to prevent re-load
    children: [
      {
        path: 'user/:id',
        children: [
          {
            path: 'contact',
            component: UserMasterComponent,
            children: [
              {
                path: '',
                component: ContactComponent,
                outlet: 'detail'
              }
            ]
          },
          {
            path: 'profile',
            component: UserMasterComponent,
            children: [
              {
                path: '',
                component: ProfileComponent,
                outlet: 'detail'
              }
            ]
          }
        ]
      }
    ]
  }
};