Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple named router-outlet - component imported but not initialized and rendered

I'm using multiple named angular 8 router-outlet in a web app. All the routerLink seems to work as it changes the URL but components in my 2nd router-outlet are imported but not initialized nor rendered.


I made a Stackblitz available here : https://stackblitz.com/edit/ng-multiple-router-outlet?file=src/app/app.component.ts

As you can see, when you click on the sidebar, under photos you have a second navigation level by clicking on Google or Facebook but nothing is rendered.

In modules, components used in other modules and RouterModule are well exported to be accessible, I don't see what I've done wrong.

I tried to declare the routes with both forRoot and forChild methods, I put some logs, but I'm running out of clues.

Thanks for your help !

like image 660
Adrien Martinet Avatar asked Aug 09 '19 13:08

Adrien Martinet


1 Answers

Angular router is pretty simple once you understand how nested routes works there.

Let's imagine a simple configuration:

RouterModule.forRoot([
  { 
    path: '',
    component: HomeComponent,
    children: [
       { path: 'child', component: ChildComponent }
    ]
  }
])

How would you use router-outlet to cover all routes above?

app.component.html
     \
   contains
       \
    <router-outlet></router-outlet>
                 \/
             renders
                  \
              HomeComponent
             home.component.html
                  \
               contains
                    \
               <router-outlet></router-outlet>
                   renders
                       \
                     ChildComponent

The main takeaway here is that router-outlet renders component depending on router context. Once it renders component a new context is created and all router-outlet's declared at this level will look at children configuration.

The same is true for named routes.

You've generated the link like:

(selection:facebook//sidebar:photos)

It means that these named routes should be at the same root level. But you defined <router-outlet name="selection"></router-outlet> at nested level inside rendered by router LibraryComponent.

Let's add this outlet at the same level as 'sidebar':

<router-outlet name="sidebar"></router-outlet>
<router-outlet name="selection"></router-outlet>

and it actually works stackblitz


Now let's come back to your attempt. If you want to render selection components inside selection.component.html then you should be using nested named routed links:

selection.component.html

[routerLink]="['.', { outlets: { selection: [routeName] } }]"
                \/
           relative path

The above binding will generate nested links like (sidebar:photos/(selection:facebook))

Now you need to move SelectionRoutes configuration to children property of photos path:

selection.module.ts

imports: [
  CommonModule,
  RouterModule, //.forChild(SelectionRoutes)
],

sidebar.routes.ts

import { SelectionRoutes } from '../selection/selection.routes';
...
export const SidebarRoutes: Route[] = [
  { path: 'photos', component: LibraryComponent, outlet: 'sidebar', children: SelectionRoutes },

Stackblitz Example

Update

In order to make facebook as a default subroute you create a route with redirectTo option like:

export const SelectionRoutes: Route[] = [

  { path: 'facebook', component: FacebookComponent, outlet: 'selection' },
  { path: 'google', component: GoogleComponent, outlet: 'selection' },
  { path: '', redirectTo: '/(sidebar:photos/(selection:facebook))', pathMatch: 'full', },
]

Stackblitz Example

like image 145
yurzui Avatar answered Sep 21 '22 09:09

yurzui