Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sub-Module child routes not working ("Error: Cannot match any routes.")

Tags:

angular

routes

I'm using Angular 6.0.3. I have a sub-module called "Admin" with three components. Admin's root component ("AdminComponent") route works fine (path: ""), but I can't seem to trigger any of the others. Why can't Angular find my routes?

routes.ts

import { Routes } from "@angular/router";
import { SplashComponent } from "./splash/splash.component";
import { LoginComponent } from "./login/login.component";
import { WatchComponent } from "./watch/watch.component";

import { AdminComponent } from "./admin/admin/admin.component";
import { HomeComponent as AdminHomeComponent } from "./admin/home/home.component";
import { AddSongComponent } from "./admin/add-song/add-song.component";
import { AdminGuard } from "./auth/admin.guard";

export const appRoutes: Routes = [
  {
    path: "",
    children: [
      { path: "", component: SplashComponent, pathMatch: "full" },
      { path: "login", component: LoginComponent, pathMatch: "full" },
      { path: "watch", component: WatchComponent, pathMatch: "full" },
      {
        path: "admin",
        component: AdminComponent,
        pathMatch: "full",
        canActivate: [AdminGuard],
        children: [
          {
            path: "",
            component: AdminHomeComponent,
            pathMatch: "full",
            outlet: "admin"
          },
          {
            path: "add-song",
            component: AddSongComponent,
            pathMatch: "full",
            outlet: "admin"
          }
        ]
      }
    ]
  }
];

admin/admin/admin.component.html

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

admin/home/home.component.html

<div>

   <a mat-raised-button [routerLink]="['add-song']">Add new song</a>

</div>

note: I've also tried [routerLink]="[{ outlets: { admin: ['add-song'] } }], still route not found.

like image 208
zakdances Avatar asked Jul 09 '18 00:07

zakdances


3 Answers

I would recommend you to look at Lazy-loading feature while loading sub modules, which is the correct way to load when you have many modules.

In your case you have admin module as a sub module, so here is the routing Configuration,

 RouterModule.forRoot([
      { path: '', redirectTo: 'splash', pathMatch: 'full' },
      { path: 'splash', component: SplashComponent },
      { path: 'admin', loadChildren: './admin/admin.module#AdminModule' },
      { path: '**', component: NotFoundComponent }
    ], { enableTracing: true })]

and the Admin.module routing is as follows,

RouterModule.forChild([
      {
        path: '', component: AdminComponent,
        children: [

          { path: '', component: AdminHomeComponent }
          ,
          { path: 'add-song', component:  AddSongComponent}]
      }
  ])
  ]

WORKING STACKBLITZ DEMO

ROUTES:

Splash

  • https://nested-routes-angular-lazyloading.stackblitz.io/splash

Admin

  • https://nested-routes-angular-lazyloading.stackblitz.io/admin

Admin-AddSong

  • https://nested-routes-angular-lazyloading.stackblitz.io/admin/add-song
like image 156
Sajeetharan Avatar answered Oct 21 '22 21:10

Sajeetharan


Have you tried to create Admin related components in its own module? Then you can create a admin-routing.module.ts

const adminRoutes: Routes = [
  {
    path: '',
    component: AdminComponent,
    children: [
      {
        path: '',
        children: [
          { path: 'add-song', component: AddSongComponent },
          { path: 'something-else', component: SomeOtherComponent },
          { path: '', component: AdminDefaultComponent }
        ]
      }
    ]
  }
];

@NgModule({
  imports: [ 
    RouterModule.forChild(adminRoutes)
  ],
  exports: [
    RouterModule
  ]
})
export class AdminRoutingModule {}

Then in your main app-routing.module you can refer to it as

const appRoutes: Routes = [
  { path: '', component: SplashComponent },
  { path: 'login', component: LoginComponent },
  {
    path: 'admin',
    loadChildren: 'app/admin/admin.module#AdminModule',
  },
  { path: '**', component: SomeOtherComponent }
];

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

edit: I noticed that you did create its own sub module, so you'll need to create a routing-module for this sub-module.

like image 36
DavidZ Avatar answered Oct 21 '22 22:10

DavidZ


This might be late reply, but i would like to focus on 1 important thing, angular compiler is very smart which detects on which root you currently on.So if you are calling any nested route from .html template it will automatically checks your current route in the url and what ever route you want this will simply append this to current route.

In simple terms, What you are trying to do in your code from admin/home/home.component.html you are trying to trigger add-song route and it will give you result as admin/add-song doesn't exist.This is pretty much expected though

sharing routes config. for children and some other code snippet.

children: [
      {
        path: "admin-home",
        component: AdminHomeComponent,
        pathMatch: "full",
        outlet: "admin"
      },
      {
        path: "add-song", 
        component: AddSongComponent, 
        pathMatch: "full",
        outlet: "admin"
      },
      {path: '', 
      redirectTo:'admin-home', 
      pathMatch: 'full'}
    ]

now from your admin/home/home.component.html use below routerLink

  <div>
    <a mat-raised-button [routerLink]="['/add-song']">Add new song</a>
  </div>

Untill now you were trying to add relative path, In angular specially in routerLink, it will detect current path and will append expected path to the end of your current path.so it will give you error.So try to provide absolute path in your nested routes.

But this.router.navigate() method won't understand it's current route automatically.It always starts route from root route.i.e if you are trying to call nested path from .ts file then angular won't recognize current path.So if you willing to tell angular that which is current route then from .ts file you can do something like this

import { ActivatedRoute, Router } from '@angular/router';
...
constructor(private route: ActivatedRoute, private router: Router) { }
...
this.router.navigate(['./add-song'], {relativeTo: this.route}); 

One more thing is like <a mat-raised-button [routerLink]="['add-song']">Add new song</a> this is as same as <a mat-raised-button [routerLink]="['./add-song']">Add new song</a> Or <a mat-raised-button [routerLink]="['../add-song']">Add new song</a> this is relative path, you must use absolute path

Otherwise try calling your route from .ts component without relativeTo property and relative path.

Hope this may work for you

like image 28
Prasanna Avatar answered Oct 21 '22 22:10

Prasanna