Angular2+ | How to define routing with params in NgModule

Viewed 119

I'm quite new with Angular routing and couldn't find any solution for this case. I've got a Login component and a User module. There's one <router-outlet> in App component, one in UserBase component in User module. Here's my routing declaration.

app.module.ts

const routes: Routes = [
  {
    path: 'login',
    component: LoginComponent
  },
];

imports: [
    RouterModule.forRoot(routes),
    UserModule,
],

user.module.ts

const routes: Routes = [
  {
    path: ':username',
    component: UserBaseComponent,
    children: [
      {
        path: '',
        component: UserDetailsComponent,
      },
      {
        path: 'progress',
        component: ProgressComponent,
      },
      {
        path: 'timeline',
        component: TimelineComponent,
      },
      {
        path: 'leaderboard',
        component: LeaderboardComponent,
      }
    ],
  }
];

imports: [
    RouterModule.forChild(routes)
]

It works fine with the path for user module, but it keeps recognizing 'login' as an username and not navigate to Login component. Actually, if I add a static path before the param like this, it works correctly.

{
  path: 'user',
  children: [
    {
      path: ':username',
      component: UserBaseComponent,
      children: [
        {
          path: '',
          component: UserDetailsComponent,
        },
        {
          path: 'progress',
          component: ProgressComponent,
        },
        {
          path: 'timeline',
          component: TimelineComponent,
        },
        {
          path: 'leaderboard',
          component: LeaderboardComponent,
        }
      ],
    }
  ]
}

Could anyone explain why?

3 Answers

When you import modules with their own routing inside your main module the routes for the sub modules are placed in front of the main routes.

So you're routing looks like this when you import the UserModule.

- :username
    - /
    - progress

- login

When the routing is read it starts at the top, so :username is read first. That route matches everything, so no other route will be accessed.

You can try and lazy load your user module, this way you are in control of the order of routes. Notice that you don't declare the UserModule as an import anymore.

const routes: Routes = [
  {
    path: 'login',
    component: LoginComponent
  },
  {
    path: '',
    loadChildren: '<PATH_TO_MODULE>/user.module#UserModule'
  },
];

imports: [
    RouterModule.forRoot(routes)
]

Here is a Stackblitz: https://stackblitz.com/edit/ng-stackoverflow-52391592

Your user.module is also working. but it will work if your URL have like this : https:\\www.google.com\2

path: ':username',
component: UserBaseComponent,
children: [
     {
        path: '',
        component: UserDetailsComponent,
      },
]

and below code work with https:\\www.google.com\user\2.

path: 'user',
children: [
    {
      path: ':username',
      component: UserBaseComponent,
      children: [
          {
            path: '',
            component: UserDetailsComponent,
          },
     }
]

In the second code of your user.module, You had not define any component just define its childs. So when your run your child component it will run as sibling not as children component.

Because If you want to run children component inside parent component that you must need to define more <router-outlet> inside your parent component.

The angular give default <router-outlet> inside app.component.html when you create application.

Here is the working Stackblitz with parent-child and with params. That you can modify as per your requirement.

When you declare your username path as ":username" it'll take any given string from the root url as a valid param to your UserBaseComponent. That's why your "login" string is being directed to the UserBaseComponent.

For example, your url is: 'jam.com'.

'jam.com/:username' causes any 'jam.com/xxxxxx' to be a valid param for UserBaseComponent - that includes 'jam.com/login'.

You already solved it - by creating a static path before the params to explicitly differentiate it from /login.

Related