How to fix ERROR Uncaught (in promise): Error: Cannot match any routes when clicking on row with navigation in Material Angular table?

Issue

A Material Angular table lists items (events as in "volunteering events").

Following https://careydevelopment.us/blog/angular-material-tables-how-to-make-clickable-rows-that-take-users-to-a-new-route, I implemented a function, "getEventDetail", meant to allow to navigate to a detail page when a row in the list table is clicked.

But console returns the following message:
"ERROR Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: ‘admin-events/details’"

Here is the admin-event.component.ts file:

import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/core';
import {merge, Observable, of as observableOf} from 'rxjs';
import {catchError, map, startWith, switchMap} from 'rxjs/operators';
import {ResponseApi} from '../../models/api';
import {EventService} from '../../services/event.service';
import {Event} from '../../models/event';
import {MatTableDataSource} from '@angular/material/table';
import {Router} from "@angular/router";


@Component({
  selector: 'app-admin-events',
  templateUrl: './admin-events.component.html',
  styleUrls: ['./admin-events.component.scss']
})
export class AdminEventsComponent implements OnInit {

  eventList$: Observable<Event[]>;  
  eventList: MatTableDataSource<Event>;
  
  an_event: any;

  displayedColumns: string[] = [
    'description',
    'start_time',
    'end_time',
    'cell',
    'task_type'
  ];


  constructor(private eventService: EventService,
    private router: Router,
    ) { }
      
    ngOnInit(): void {
      this.getEvents();
      this.getEventDetail(this.an_event);
 
    }
  
    getEvents(): void {
      this.eventService.list().subscribe(
        (responseApi: ResponseApi<Event>) => {
          this.eventList = new MatTableDataSource(responseApi.results);
      })
    }
  
    getEventDetail(an_event: Event) {
      let route = '/admin-events/details/';
      this.router.navigate([route], { queryParams: { id: an_event.id } } );
    }

Here is an excerpt from the html file:


  <mat-table class="events__content__table" [dataSource]="eventList">


  <ng-container matColumnDef="description">
      <mat-header-cell *matHeaderCellDef 
      class="events__content__table__header">
      Description</mat-header-cell>
      <mat-cell class="events__content__table__cell--text"
                *matCellDef="let item">{{item.description}}

              </mat-cell>
  </ng-container>

(...)

  <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
  
  <mat-row mat-row 
  (click)="getEventDetail(row)"
  *matRowDef="let row; columns: displayedColumns"></mat-row>
 
</mat-table>

Here is an excerpt from the app-routing.module.ts file:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { LoginComponent } from './pages/login/login.component';
import {DefaultLayoutComponent} from "./layouts/default-layout/default-layout.component";
import {ProfileComponent} from "./pages/profile/profile.component";
import {ScheduleComponent} from "./pages/schedule/schedule.component";
import {EventsComponent} from "./pages/events/events.component";
import {CanActivateViaAuthGuard} from './guards/CanActivateViaAuthGuard';
import {CellsComponent} from './pages/cells/cells.component';
import {RegisterConfirmComponent} from "./pages/register-confirm/register-confirm.component";
import {CkEditorPageComponent} from "./pages/ck-editor-page/ck-editor-page.component";
import {MobileComponent} from "./pages/mobile/mobile.component";
import {LogoutComponent} from "./pages/logout/logout.component";
import {AdminLayoutComponent} from "./layouts/admin-layout/admin-layout.component";
import { AdminDashboardComponent } from './pages/admin-dashboard/admin-dashboard.component';
import { AdminEventsComponent } from './pages/admin-events/admin-events.component';
import { AdminEventDetailsComponent } from './pages/admin-events/admin-event-details/admin-event-details.component';


const routes: Routes = [

(...)

  {
    path: '',
    component: AdminLayoutComponent,
    children: [
      {
        path: 'admin-dashboard',
        component: AdminDashboardComponent,
      },
      {
        path: 'admin-events',
        component: AdminEventsComponent,
      },
      {
        path: 'admin-events/details/:id',
        component: AdminEventDetailsComponent,
      }    
    ]
  },
];

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

Any help would be greatly appreciated.

Solution

According to Route definition with a parameter,

Embedding the route parameter token, :id, in the route definition path
is a good choice for this scenario because the id is required by the
HeroDetailComponent and because the value 15 in the path clearly
distinguishes the route to "Magneta" from a route for some other hero.

Hence, :id is required for admin-events/details route and you cannot pass in with queryParams as queryParams is for optional params.

{
  path: 'admin-events/details/:id',
  component: AdminEventDetailsComponent,
}  

Solution

You have to set the route parameter as below:

getEventDetail(an_event: Event) {
  let route = '/admin-events/details/';
  this.router.navigate([route, an_event.id]);
}

Sample Solution on StackBlitz

Answered By – Yong Shun

Answer Checked By – Marilyn (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.