1

I run into troubles when using multiple router-outlet.

I would like to use 2 router-outlet at the same time. Here a hierarchical view of the components display on which outlet and which url:

  • outlet 1: app-list => url: /app
    • outlet 2: app-detail (optional) => url: /app/1
  • outlet 1: srv-list => url: /srv
    • outlet 2: srv-detail (optional) => url: /srv/1

For example, srv-detail should not be displayed when the app-list is.

This is my attempt (I've reduced my code the most I could). There is no error in the browser console. :( And I'm confused when manipulating named router-outlets.

app-list-component.ts:

import { Component } from '@angular/core';

@Component({
  selector: 'app-list',
  template: '<h2>AppList</h2>',
  styleUrls: []
})
export class AppListComponent {}

app-detail-component.ts:

import { Component } from '@angular/core';

@Component({
  selector: 'app-detail',
  template: '<h2>App Detail</h2>',
  styleUrls: []
})
export class AppDetailComponent {}

srv-list-component.ts:

import { Component } from '@angular/core';

@Component({
  selector: 'srv-list',
  template: '<h2>Srv list</h2>',
  styleUrls: []
})
export class SrvListComponent {}

srv-detail-component.ts:

import { Component } from '@angular/core';

@Component({
  selector: 'srv-detail',
  template: '<h2>Srv detail</h2>',
  styleUrls: []
})
export class SrvDetailComponent {}

app.component.ts:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template:
    '<div><h1>Title 1</h1><router-outlet name="menu"></router-outlet></div>' +
    '<div><h1>Title 2</h1><router-outlet name="content"></router-outlet></div>',
  styleUrls: []
})
export class AppComponent {
  /* In future, by subscribing to the router, we will be able to hide the content
  outlet if there is only one '/' in the route (eg. /app and not /app/3) */
}

app.module.ts:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { AppComponent } from './app.component';
import { AppListComponent } from './app-list.component';
import { AppDetailComponent } from './app-detail.component';
import { SrvListComponent } from './srv-list.component';
import { SrvDetailComponent } from './srv-detail.component';

const routes : Routes = [
  {
    path: '',
    pathMatch: 'full',
    redirectTo: 'app'
  },

  {
    path: 'app',
    component: AppComponent,
    children: [
      {
        path: '',
        component: AppListComponent,
        outlet: 'menu'
      },
      {
        path: ':id',
        component: AppDetailComponent,
        outlet: 'content'
      }
    ]
  },

  {
    path: 'srv',
    component: AppComponent,
    children: [
      {
        path: '',
        component: SrvListComponent,
        outlet: 'menu'
      },
      {
        path: ':id',
        component: SrvDetailComponent,
        outlet: 'content'
      }
    ]
  }
]

@NgModule({
  declarations: [
    AppComponent,
    AppListComponent,
    AppDetailComponent,
    SrvListComponent,
    SrvDetailComponent
  ],
  imports: [
    BrowserModule,
    RouterModule.forRoot(routes)
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Do you guys have some ideas? Thanks.

Edit : The plunker.

Cerdicipe
  • 188
  • 3
  • 13

1 Answers1

2

I'm running into problems running your project, but I will try again later. If you got any Plunker or git it will be great.

one thing I would like you to try is to remove the component property and value before the children array from each route.

path: 'srv',
component: AppComponent,<--this one on each route
children: [...]

since the route get the component it should load from the exact route only, this declared on child level

please let me know if it's help and I will try to explore more later on.

Edit:

This is the fixed route:

const routes : Routes = [
  {
    path: '',
    pathMatch: 'full',

    /* Below is just a test because there is some issues
    with punkler and url changing */
    //redirectTo: 'app', //Does work
    redirectTo: 'app/3', //Does not work
    //redirectTo: 'srv', //Does work
    //redirectTo: 'srv/3', //Does not work
  },
  {
    path: 'app',
    children: [
      {
        path: '',
        outlet: 'menu',
        component: AppListComponent
      },
      {
        path: ':id',
        children:[
          {
            path:'',
            outlet: 'content',
            component: AppDetailComponent,
          }
        ]
      }  
    ]
  },
  {
    path: 'srv',
    children: [
        {
          path:'',
          component: SrvListComponent,
          outlet: 'menu',
        },
        {
          path: ':id',
          children:[
            {
              path:'',
              component: SrvDetailComponent,
              outlet: 'content'
            }
          ]
        }
    ]
  }
];

keep in your mind that each route who may have another level should contain the children with 1 object with path:"", which means itself and n other object of n paths

Example from yours use case:

const routes = [{
path: 'app',
children: [
   //self route -> /app
  {
    path: '',
    outlet: 'menu',
    component: AppListComponent
  },
  {
    //still not saying there is /app/:id route
    path: ':id',
    children:[
      {
      //declaration for /app/:id route
        path:'',
        outlet: 'content',
        component: AppDetailComponent,
      }
    ]
  }  
]
}]

Edit 2:

Router outlet requirement

The app still will throw some errors since you don't have any nameless router outlet, this is must be in your html. So you should either replace the content/menu router-outlet with nameless one or add another router-outlet.

Nameless router-outlet:

<router-outlet></router-outlet>
OB1.K
  • 52
  • 4
  • Thanks, now the components of type "list" work. But there is still some problems with "detail" components. Also, I've added a plunker on my question. – Cerdicipe Jun 29 '17 at 23:04
  • Thank you. it works (except the router links but it does not matter). The new plunker: https://plnkr.co/edit/f7aRluiI9Y1LHmtTZ8of?p=preview You put me in the right direction. I found a better solution to answer my problem inspired from Madhu Ranjan's solution: https://stackoverflow.com/a/42516757/5153648. But I have one more question: why Angular2 need to have a children attribute for `path: "id"` although there is only one possible route? – Cerdicipe Jul 04 '17 at 14:17
  • Glad to hear I helped you. Another small thing, I saw on the last plunker you still don't have any nameless router-outlet, this will make issue while moving between routes, consider remove the content name so it'll be nameless router-outlet (don't forget to remove the outlet property from the config { ...outlet: 'content'} – OB1.K Jul 04 '17 at 18:13
  • 1
    About the children, while making children you can think about any child route as the main route for his level which you can use for redirect and pathMatch, like this- children:[{path:'',redirectTo: 'list', pathMatch: 'full',component: SrvDetailComponent, outlet: 'content' },{path:'list',component: SrvDetailComponent,outlet: 'content'}] – OB1.K Jul 04 '17 at 18:17