Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 - Routing not working when using router-outlet name

I'm trying to give a name to the router-outlet but it is not working.

This is the basic routing that works perfectly:

routing module

@NgModule({
  imports: [
    RouterModule.forChild([
      {
        path: 'admin',
        component: AdminComponent,
        children: [
          {
            path: '',
            redirectTo: 'dashboard1',
            pathMatch: 'full'
          },
          {
            path: 'dashboard1',
            component: AdminDashboard1Component
          },
          {
            path: 'dashboard2',
            component: AdminDashboard2Component
          }
        ]
      }
    ])
  ],
  exports: [
    RouterModule
  ]
})
export class AdminRoutingModule { }

component html

<div class="wrapper">

  <app-admin-header></app-admin-header>
  <!-- Left side column. contains the logo and sidebar -->
  <app-admin-left-side></app-admin-left-side>

  <!-- Content Wrapper. Contains page content -->
  <router-outlet></router-outlet>

  <!-- /.content-wrapper -->
  <app-admin-footer></app-admin-footer>

  <!-- Control Sidebar -->
  <app-admin-control-sidebar></app-admin-control-sidebar>
  <!-- /.control-sidebar -->
</div>

Now I want to give a name to the router-outlet in order to implement some customizations but it doesen't work.

If I apply this changes:

 <router-outlet name='one'></router-outlet>

and:

imports: [
    RouterModule.forChild([
      {
        path: 'admin',
        component: AdminComponent,
        children: [
          {
            path: '',
            redirectTo: 'dashboard1',
            pathMatch: 'full'
          },
          {
            path: 'dashboard1',
            component: AdminDashboard1Component,
            outlet:'one'
          },
          {
            path: 'dashboard2',
            component: AdminDashboard2Component
            outlet:'one'
          }
        ]
      }
    ])
  ]

The routing is not working:

/admin : the application is loaded but noone component is injected

/admin/dashboard1 : the application is not loaded and I get this error in console: Error: Cannot match any routes. URL Segment: 'admin/dashboard1'

Thanks to support

like image 990
DarioN1 Avatar asked Feb 08 '18 10:02

DarioN1


1 Answers

The problem lies in how you are trying to access your pages.

Let's start with your routing configuration.

@NgModule({
  imports: [
    RouterModule.forChild([
      {
        path: 'admin',
        component: AdminComponent,
        children: [
          {
            path: '',
            redirectTo: 'dashboard1',
            pathMatch: 'full'
          },
          {
            path: 'dashboard1',
            component: AdminDashboard1Component,
            outlet:'one'
          },
          {
            path: 'dashboard2',
            component: AdminDashboard2Component,
            outlet:'one'
          }
        ]
      }
    ])
 ],it attempts to perform a 
  exports: [
    RouterModule
  ]
})
export class AdminRoutingModule { }

At face value, the configuration seems to be correct, however, it is not correct to the way you want to use it.

When the AdminRoutingModule is loaded lazily, the path admin is rendered in the context of a <router-outlet></router-outlet> that is found within some parent component, which for this example we'll call it BaseComponent whose content is

@Component({ template: '<router-outlet></router-outlet'})
export class BaseComponent {
}

and is tied to the following routing config (note that this is to explain what is happening).

@NgModule({
  imports: [
    RouterModule.forRoot([
      {
        path:'', component:BaseComponent,
        children: [
          { path:'a', loadChildren:'some-path/admin-routing.module#AdminRoutingModule // This will be loaded in the router-outlet found within the BaseComponent
        ]
      }
    ]), ...
 ],
 declerations: [...]
 bootstrap: [...]
})
export class AppModule { }

...Back to your routing config

RouterModule.forChild([
  {
    path: 'admin',
    component: AdminComponent,
    children: [
      {
        path: '', // Tied with the main router-outlet
        redirectTo: 'dashboard1',
        pathMatch: 'full'
      },
      {
        path: 'dashboard1', // Tied with a named outlet
        component: AdminDashboard1Component,
        outlet:'one'
      },
      {
        path: 'dashboard2', // Tied with a named outlet
        component: AdminDashboard2Component,
        outlet:'one'
      }
    ]
  }
])

Note that the above config ties the base path denoted with path: '' to a base outlet. On the other hand paths dashboard1 and dashboard2 are tied to another outlet, that is named outlet one.

Since the base path is tied to the base outlet, the redirect that is configured, ie, redirect to dashboard1, is attempted on the base outlet. Since, using the above configuration, no dashboard1 is configured with the base outlet, the redirection fails with the error specifying that no outlet exists with that url is (this is the correct behavior).

Simply put, you cannot redirect with the above config, from one router outlet, to a different one, because simply put, within the redirect there is nothing that specifies that it should be rendering to a different outlet. This is also why removing the outlet:'one' from your config would work, because redirecting would be happening in the same outlet tree.

Solution

You cannot perform a redirect like you are mentioning. However there are solutions to achieve what you want.

In your AdminComponent have both outlets present, as below

<!-- Content Wrapper. Contains page content -->
<router-outlet></router-outlet>
<router-outlet name="one"></router-outlet>

Add a component to your base path, which upon init, performs the navigation that you require like so...

In your routing config

{
    path: '', component: MyBaseAdminComponent
},

In your MyBaseAdminComponent

@Component({ template: '' })
export class MyBaseAdminComponent implements OnInit {
    constructor(private router:Router;) {}

    ngOnInit() {
       this.router.navigate([ { outlet: { one: [ 'dashboard1' ] } ]);
    }
}

The above should give you the solution you require.

Here's a working plunker to demonstrate the above behavior, and routing to auxiliary routes.

like image 144
JeanPaul A. Avatar answered Sep 19 '22 23:09

JeanPaul A.