Home > Software engineering >  Angular cannot navigate to nested non-child component
Angular cannot navigate to nested non-child component

Time:04-21

This is in Angular 12. I have a payments controller in ClientApp/src/app with (not showing all code) payments.module.ts:

import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { PaymentsComponent } from "./payments.component";

@NgModule({
  imports: [RouterModule.forChild([{path: 'payments',component: PaymentsComponent}])],
  declarations: [PaymentsComponent]
})
export class PaymentsModule {}

and payments.component.ts:

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

@Component({
  selector: 'app-payments',
  templateUrl: './payments.html'
})
export class PaymentsComponent implements OnInit {

  constructor(...) { ... }

  ngOnInit(): void {...    });
  }
}

PaymentsModule is only referenced in app.module.ts:

import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
...
import { AppComponent } from './app.component';
import { AppRouterModule } from './app-router.module';
import { PaymentsModule } from "./payments/payments.module";
....

@NgModule({
  declarations: [AppComponent],
  imports: [
    HttpClientModule,
    PaymentsModule,
    AppRouterModule,
    .....
  ],
  ...
  bootstrap: [AppComponent],

})
export class AppModule {}

There is no reference to PaymentsComponent in app-router.module.ts. File app.component.html has an <app-menu> selector, and that selector contains a mat-menu-item which has no problem navigating to Payments:

<button mat-menu-item [routerLink]="['/payments']">Payments</button>

I want to place a process-payment component within the payments component, however I do not want the process-payment component to be a child component of payments. I want to navigate to process-payment directly via another mat-menu-item. The code for process-payment is as basic as what I've shown above for the two payments files, and I added the same references in app.module.ts:

import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
...
import { AppComponent } from './app.component';
import { AppRouterModule } from './app-router.module';
import { PaymentsModule } from "./payments/payments.module";
import { ProcessPaymentModule } from "./payments/process-payment/process-payment.module"; //added here
....

@NgModule({
  declarations: [AppComponent],
  imports: [
    HttpClientModule,
    PaymentsModule,
    ProcessPaymentModule, //added here
    AppRouterModule,
    .....
  ],
  ...
  bootstrap: [AppComponent],

})
export class AppModule {}

However a new menu item cannot find my new component, I get a 404 Not found error with no details:

<button mat-menu-item [routerLink]="['/payment/process-payment']">Process Payment</button>

I've tried different paths for routerLink, but always get redirected to my page not found component. Not understanding how/why the new component cannot be found, the process-payment structure and reference is the same as payments. Can anyone help or shed some light as to the problem, other than me as the problem? :) Thanks, BB.

CodePudding user response:

I think you're trying to have nested routes. Basically, you should have a <router-outlet> inside payments.component.ts and add children to your path payments in payments.module.ts.

payments.component.html

<h1>Payments</h1>

<a mat-menu-item [routerLink]="['process-payment']">Process Payment</a>

<!-- Children route will be inserted here -->
<router-outlet></router-outlet>

payments.module.ts:

@NgModule({
  imports: [
    RouterModule.forChild([
      {
        path: 'payments',
        component: PaymentsComponent,
        children: [
          {
            path: 'process-payment',
            component: ProcessPaymentComponent
          }
        ]
      }
    ])
  ],
  declarations: [PaymentsComponent]
})
export class PaymentsModule {}

If you want to navigate to process-payment from app-component or elsewhere, the routerLink would be ['/payments/process-payment']

You can find the documentation for nesting routes here: https://angular.io/guide/router#nesting-routes

EDIT

If you do not want nested routes and only keep them flat with a single router-outlet, then you just need to add a new route for ProcessPaymentComponent.

@NgModule({
  imports: [
    RouterModule.forChild([
      {
        path: 'payments',
        component: PaymentsComponent
      },
      {
        path: 'payment/process-payment',
        component: ProcessPaymentComponent
      }
    ])
  ],
  declarations: [PaymentsComponent]
})
export class PaymentsModule {}

Then just link to the page like you tried before:

<button mat-menu-item [routerLink]="['/payment/process-payment']">Process Payment</button>
  • Related