Igor Zinchenko
Igor Zinchenko

Reputation: 353

Angular routing gives incorrect component

I have an issue with angular routing. When I try to go to the my.domain/new-york I've got correct page (HomeComponent) But when I try to go to the my.domain/new-york/search I've got HomeComponent to instead SearchComponent. What I did wrong?

const routes: Routes = [
  {
    path: '',
    component: BasicComponent,
    children: [
      {
        path: '',
        component: HomeComponent,
        data: {
          headerDark: true
        }
      },
      {
        path: ':city',
        component: HomeComponent,
        data: {
          headerDark: true
        },
        children: [
          {
            path: ':category',
            component: HomeComponent
          },
          {
            path: 'search',
            component: SearchComponent,
            data: {
              headerDark: true
            }
          },
        ]
      },
    ]
  }
];

UPD: I use two modules:

const routes: Routes = [
  {
    path: '',
    loadChildren: () => import('./modules/basic/basic.module').then(mod => mod.BasicModule),
    runGuardsAndResolvers: 'always'
  },
  {
    path: 'dashboard',
    canActivate: [AuthService],
    loadChildren: () => import('./modules/dashboard/dashboard.module').then(mod => mod.DashboardModule)
  },
  {
    path: '**',
    redirectTo: '/'
  }
];

UPD 2: Example https://stackblitz.com/edit/angular-ghafx6?file=src%2Fapp%2Forders%2Forders-routing.module.ts

Upvotes: 3

Views: 2187

Answers (3)

mandrag.ora
mandrag.ora

Reputation: 11

The answer of @KShewengger didn't work for me because I didn't want the ChildComponents (SearchComponent) to be rendered inside the ParentComponent (HomeComponent). In my case I was only using the routing config to construct a breadcrumb. My ChildComponents however should always be rendered in my global <router-outlet> in my AppComponent completely replacing the ParentComponent in the DOM

My solution ended up like this:

{
   path: ':city',
   children: [
      {
        path: '',
        component: HomeComponent,
      },
      {
        path: 'search',
        component: SearchComponent,
      }
      {
        path: ':category',
        component: HomeComponent
      }
    ]
},

A bit of explanation (although I'm no 100% sure about that): If you have childroutes, you always need a <router-outlet> in the ParentComponent. Else the child routes are pretty much ignored.

Changing the path: ':city' to be a componentless route was crucial here, so that my SearchComponent got rendered in the end.

I'm still quite the Angular noob and can't explain all the internals, but I hope this might help someone in the future.

Upvotes: 0

Vivek Jain
Vivek Jain

Reputation: 2864

Order of routes are very important if you are using dynamic routes.

Here issue is issue is search after city name is consider as category because category is a dynamic route and it comes before static route. So it is always recommended that dynamic route must comes at the end.

For your problem change you routes this way will solve your problem.

 const routes: Routes = [
  {
    path: '',
    component: BasicComponent,
    children: [
      {
        path: '',
        component: HomeComponent,
        data: {
          headerDark: true
        }
      },
      {
        path: ':city',
        component: HomeComponent,
        data: {
          headerDark: true
        },
        children: [
          {
            path: 'search',
            component: SearchComponent,
            data: {
              headerDark: true
            }
          },
          {
            path: ':category',
            component: HomeComponent
          },
        ]
      },
    ]
  }
];

See the Stackblitz for reference

EDITED

As per your stackblitz below 2 changes required.

  1. city.component.html

    added <router-outlet></router-outlet>

  2. orders.component.html

    <a [routerLink]="['/new-york']">
      City
    </a>
    <a [routerLink]="['/new-york/shops']">
      Category
    </a>
    <a [routerLink]="['/new-york/search']">
      Search
    </a>
    <router-outlet></router-outlet>

See the Stackblitz for reference

Upvotes: 3

KShewengger
KShewengger

Reputation: 8269

This is because in your code, you have initialized the /:category first before the search so the search keyword was being read as a category parameter.

Try to reorder the routes to:

children: [
  {
     path: 'search',
     component: SearchComponent,
     data: {
       headerDark: true
     }
  },
  {
     path: ':category',
     component: HomeComponent
  },
]

UPDATE:

You can also try multiple parameter instances using this method. Take note of the order.

Method #1:

Attached StackBlitz Demo for your reference. You can check it's console as well

children: [
  {
    path: ':city/search',
    component: SearchComponent
  },
  { 
    path: ':city/:category',
    component: HomeComponent,
  },
  { 
    path: ':city',
    component: HomeComponent
  }
]

Method #2:

Based on your routes above and upon testing what you wanted to do on those routes under the :city is that you wanted to render those components under the CityComponent or in your case at HomeComponent but no children is being rendered?

This is because you need to add a <router-outlet> inside your HomeComponent to render your children components.

{
   path: ':city',                           // This is your parent route and parent component which you expect those child components below will be rendered in here. Thus, you need to specify a router-outlet in here.
   component: HomeComponent,
   ...
   children: [                              // This is your child components that will render/reflect it's templates to their parent above or in this case, inside the HomeComponent 
      {
        path: ':category',
        component: HomeComponent            // This will render the category -> home template/component inside the parent's HomeComponent
      },
      {
        path: 'search',
        component: SearchComponent,         // this will render the search template/component inside the parent's HomeComponent
      }
    ]
},

If you want to have it in distinct routes, the Method #1 solution above would help you with it.

Upvotes: 3

Related Questions