'Angular routing error cannot find parameter when redirecting to child route with parameter and outlet

I want to redirect to a child route with an outlet from a parent route with a parameter:

{
    path: "projects/:projectKey",
    component: ProjectComponent,
    canActivate: [AuthGuard],
    children: [
      { path: "artifacts", component: ArtifactsListComponent, outlet: "project-outlet", canActivate: [AuthGuard] },
      { path: "experiments", component: ExperimentsListComponent, outlet: "project-outlet", canActivate: [AuthGuard] },
      {
        path: "experiments/:experimentKey",
        component: ExperimentDetailsComponent,
        outlet: "project-outlet",
        canActivate: [AuthGuard],
      },
      { path: "runs", component: RunsListComponent, outlet: "project-outlet", canActivate: [AuthGuard] },
      {
        path: "",
        redirectTo: "/projects/:projectKey/(project-outlet:experiments)",
        pathMatch: "full",
      },
    ],
  },

When navigating to http://localhost:4200/projects/project-x, I get the following error:

Error: Uncaught (in promise): Error: Cannot redirect to '/projects/:projectKey/(project-outlet:experiments)'. Cannot find ':projectKey'.
Error: Cannot redirect to '/projects/:projectKey/(project-outlet:experiments)'. Cannot find ':projectKey'.
    at ApplyRedirects.findPosParam (router.js:2865)

If I navigate directly to http://localhost:4200/projects/project-x/(project-outlet:experiments) everything works fine.

Link to stackblitz: https://stackblitz.com/edit/angular-ivy-jcdaq1?file=src/app/app-routing.module.ts

Also, if I change the redirectTo from "/projects/:projectKey/(project-outlet:experiments)" to a path without a parameter like "/projects/project-x/(project-outlet:experiments)" it seems to work.

Anyone has a solution for having parameters and outlets in redirectTo path of child components?



Solution 1:[1]

I had the same problem, it because the route parameter is declared on the parent segment. you have 2 options to solve it:

  1. change the route of the redirect, so it will include the parameter, like this:
[{
     path: "path: "/projects/:projectKey/",
     redirectTo: "/projects/:projectKey/(project-outlet:experiments)",
     pathMatch: "full"
},{
    path: "projects/:projectKey/**",
    component: ProjectComponent,
    canActivate: [AuthGuard],
    children: [
      { path: "artifacts", component: ArtifactsListComponent, outlet: "project-outlet", canActivate: [AuthGuard] },
      { path: "experiments", component: ExperimentsListComponent, outlet: "project-outlet", canActivate: [AuthGuard] },
      {
        path: "experiments/:experimentKey",
        component: ExperimentDetailsComponent,
        outlet: "project-outlet",
        canActivate: [AuthGuard],
      },
      { path: "runs", component: RunsListComponent, outlet: "project-outlet", canActivate: [AuthGuard] },
    ],
  }]

OR 2. you can add redirect guard that you will activate when reaching the desired route, and do the redirect from there:

{
    path: "projects/:projectKey",
    component: ProjectComponent,
    canActivate: [AuthGuard],
    children: [
      {
        path: "experiments/:experimentKey",
        component: ExperimentDetailsComponent,
        outlet: "project-outlet",
        canActivate: [AuthGuard],
      },
      {
        path: "",
        canActivate: [RedirectGuard] 
      },
    ],
  },

class RedirectGuard {
...
  canActivate() {
      const { projectKey } =  this.route.params;
      this.router.navigateByUrl(`/projects/${projectKey}/(project-outlet:experiments)`);
  }

}

you can add more logic to make it more generic and so on...

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Moshe Shpitz