Michael Witt
Michael Witt

Reputation: 1712

Angular multiple router modules not working

I would like to have a routing module in my main app plus routing in a separate module, like:

app
 - modules
   -my-module
      my-routing.module.ts
 app-routing.module.ts

The main routing module has:

const routes: Routes = [
  { path: '', pathMatch: 'full', redirectTo: 'view-container' },
  { path: 'view-container', component: ViewContainerComponent },
  { path:  '**', component: ViewContainerComponent }
];

@NgModule({
  imports: [RouterModule.forRoot(routes, { enableTracing: true })],
  exports: [RouterModule]
})
export class AppRoutingModule { }

The sub module's routing is:

const routes: Routes = [
  { path: 'view-detail', component: CompADetailComponent }
];

@NgModule({
  imports: [
    CommonModule,
    RouterModule.forChild(routes)
  ],
  declarations: []
})
export class MyRoutingModule { }

My ViewContainer component has a routerLink to "view-detail".

<a [routerLink]="['/view-detail']">
  View Details
</a>

However, when I click on the "View Details" link, only the URL changes, the CompADetailComponent is not loaded.

I do note that if I move the "view-detail" path to the main app routing module it works fine. In the tracing, the difference I see is:

When it works:

Router Event: NavigationStart
platform-browser.js:367 NavigationStart(id: 2, url: '/view-detail')
platform-browser.js:367 NavigationStart {id: 2, url: "/view-detail"}
platform-browser.js:380 Router Event: RoutesRecognized
platform-browser.js:367 RoutesRecognized(id: 2, url: '/view-detail', urlAfterRedirects: '/view-detail', state: Route(url:'', path:'') { Route(url:'view-detail', path:'view-detail') } )
platform-browser.js:367 RoutesRecognized {id: 2, url: "/view-detail", urlAfterRedirects: "/view-detail", state: RouterStateSnapshot}
platform-browser.js:380 Router Event: GuardsCheckStart
platform-browser.js:367 GuardsCheckStart(id: 2, url: '/view-detail', urlAfterRedirects: '/view-detail', state: Route(url:'', path:'') { Route(url:'view-detail', path:'view-detail') } )
platform-browser.js:367 GuardsCheckStart {id: 2, url: "/view-detail", urlAfterRedirects: UrlTree, state: RouterStateSnapshot}
platform-browser.js:380 Router Event: ChildActivationStart
platform-browser.js:367 ChildActivationStart(path: '')
platform-browser.js:367 ChildActivationStart {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ActivationStart
platform-browser.js:367 ActivationStart(path: 'view-detail')
platform-browser.js:367 ActivationStart {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: GuardsCheckEnd
platform-browser.js:367 GuardsCheckEnd(id: 2, url: '/view-detail', urlAfterRedirects: '/view-detail', state: Route(url:'', path:'') { Route(url:'view-detail', path:'view-detail') } , shouldActivate: true)
platform-browser.js:367 GuardsCheckEnd {id: 2, url: "/view-detail", urlAfterRedirects: UrlTree, state: RouterStateSnapshot, shouldActivate: true}
platform-browser.js:380 Router Event: ResolveStart
platform-browser.js:367 ResolveStart(id: 2, url: '/view-detail', urlAfterRedirects: '/view-detail', state: Route(url:'', path:'') { Route(url:'view-detail', path:'view-detail') } )
platform-browser.js:367 ResolveStart {id: 2, url: "/view-detail", urlAfterRedirects: UrlTree, state: RouterStateSnapshot}
platform-browser.js:380 Router Event: ResolveEnd
platform-browser.js:367 ResolveEnd(id: 2, url: '/view-detail', urlAfterRedirects: '/view-detail', state: Route(url:'', path:'') { Route(url:'view-detail', path:'view-detail') } )
platform-browser.js:367 ResolveEnd {id: 2, url: "/view-detail", urlAfterRedirects: UrlTree, state: RouterStateSnapshot}
platform-browser.js:380 Router Event: ActivationEnd
platform-browser.js:367 ActivationEnd(path: 'view-detail')
platform-browser.js:367 ActivationEnd {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ChildActivationEnd
platform-browser.js:367 ChildActivationEnd(path: '')
platform-browser.js:367 ChildActivationEnd {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: NavigationEnd
platform-browser.js:367 NavigationEnd(id: 2, url: '/view-detail', urlAfterRedirects: '/view-detail')
platform-browser.js:367 NavigationEnd {id: 2, url: "/view-detail", urlAfterRedirects: "/view-detail"}

When it doesn't work:

Router Event: NavigationStart
platform-browser.js:367 NavigationStart(id: 2, url: '/view-detail')
platform-browser.js:367 NavigationStart {id: 2, url: "/view-detail"}
platform-browser.js:380 Router Event: RoutesRecognized
platform-browser.js:367 RoutesRecognized(id: 2, url: '/view-detail', urlAfterRedirects: '/view-detail', state: Route(url:'', path:'') { Route(url:'view-detail', path:'**') } )
platform-browser.js:367 RoutesRecognized {id: 2, url: "/view-detail", urlAfterRedirects: "/view-detail", state: RouterStateSnapshot}
platform-browser.js:380 Router Event: GuardsCheckStart
platform-browser.js:367 GuardsCheckStart(id: 2, url: '/view-detail', urlAfterRedirects: '/view-detail', state: Route(url:'', path:'') { Route(url:'view-detail', path:'**') } )
platform-browser.js:367 GuardsCheckStart {id: 2, url: "/view-detail", urlAfterRedirects: UrlTree, state: RouterStateSnapshot}
platform-browser.js:380 Router Event: ChildActivationStart
platform-browser.js:367 ChildActivationStart(path: '')
platform-browser.js:367 ChildActivationStart {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ActivationStart
platform-browser.js:367 ActivationStart(path: '**')
platform-browser.js:367 ActivationStart {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: GuardsCheckEnd
platform-browser.js:367 GuardsCheckEnd(id: 2, url: '/view-detail', urlAfterRedirects: '/view-detail', state: Route(url:'', path:'') { Route(url:'view-detail', path:'**') } , shouldActivate: true)
platform-browser.js:367 GuardsCheckEnd {id: 2, url: "/view-detail", urlAfterRedirects: UrlTree, state: RouterStateSnapshot, shouldActivate: true}
platform-browser.js:380 Router Event: ResolveStart
platform-browser.js:367 ResolveStart(id: 2, url: '/view-detail', urlAfterRedirects: '/view-detail', state: Route(url:'', path:'') { Route(url:'view-detail', path:'**') } )
platform-browser.js:367 ResolveStart {id: 2, url: "/view-detail", urlAfterRedirects: UrlTree, state: RouterStateSnapshot}
platform-browser.js:380 Router Event: ResolveEnd
platform-browser.js:367 ResolveEnd(id: 2, url: '/view-detail', urlAfterRedirects: '/view-detail', state: Route(url:'', path:'') { Route(url:'view-detail', path:'**') } )
platform-browser.js:367 ResolveEnd {id: 2, url: "/view-detail", urlAfterRedirects: UrlTree, state: RouterStateSnapshot}
platform-browser.js:380 Router Event: ActivationEnd
platform-browser.js:367 ActivationEnd(path: '**')
platform-browser.js:367 ActivationEnd {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ChildActivationEnd
platform-browser.js:367 ChildActivationEnd(path: '')
platform-browser.js:367 ChildActivationEnd {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: NavigationEnd
platform-browser.js:367 NavigationEnd(id: 2, url: '/view-detail', urlAfterRedirects: '/view-detail')
platform-browser.js:367 NavigationEnd {id: 2, url: "/view-detail", urlAfterRedirects: "/view-detail"}

So it seems to be picking up the "**" path instead of the "view-detail" path. Any clue what I'm doing wrong?

* EDIT * App module added:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { CompAModule } from './modules/comp-a/comp-a.module';
import { ViewContainerComponent } from './view-container/view-container.component';
import { CompADetailComponent } from './modules/comp-a-detail/comp-a-detail.component';
import { MyRoutingModule } from './modules/my-module/my-routing.module';


@NgModule({
  declarations: [
    AppComponent,
    ViewContainerComponent,
    CompADetailComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    MyRoutingModule,
    CompAModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Upvotes: 2

Views: 2345

Answers (1)

DeborahK
DeborahK

Reputation: 60626

The imports array here:

  imports: [
    BrowserModule,
    AppRoutingModule,
    MyRoutingModule,
    CompAModule
  ],

Defines the ordering of your routes. So as you have it here, Angular will merge your routes together in the following order.

  { path: '', pathMatch: 'full', redirectTo: 'view-container' },
  { path: 'view-container', component: ViewContainerComponent },
  { path:  '**', component: ViewContainerComponent }
  { path: 'view-detail', component: CompADetailComponent }

Since Angular processes routes "first match wins" ... it will always find your '**' route before your 'view-detail' route.

You just need to swap the order in the imports array:

  imports: [
    BrowserModule,
    MyRoutingModule,
    CompAModule,
    AppRoutingModule
  ],

I have a blog post that walks through the details (and exceptions) to the route ordering rules here: https://blogs.msmvps.com/deborahk/angular-route-ordering/

Upvotes: 8

Related Questions