Search code examples
angulartypescriptroutesrouterprefix

Angular routing for prefix with route parameter


I want to implement the user profile page. It would be simple to just use the

/profile/user123 path using:

app-routing.module

{
  path: 'profile',
  loadChildren: () => import('./modules/profile/profile.module').then(m => m.ProfileModule)
},

profile-routing.module

{
  path: ':username',
  component: ProfileComponent
},

however, I want to do some fancy URL like /@user123.

Unfortunately, I did not find any clues on how to do it. I tried the following:

app-routing.module

{
  path: '@:username',
  loadChildren: () => import('./modules/profile/profile.module').then(m => m.ProfileModule)
},

profile-routing.module

{
  path: '',
  component: ProfileComponent
},

but it didn't work.

There is only one thing that comes to my mind, which is using a Guard checking for the '@' prefix, otherwise redirect to the /not-found page.

Any ideas on how to do the routing using the "Angular" way?


Solution

  • You can make use of custom route matcher to achieve the expected result.

    • app-routing.module.ts
        {
          path: 'profile',
          loadChildren: () => import('./modules/profile/profile.module').then(m => m.ProfileModule)
        },
    
    • In profile-routing.module.ts you can specify a route by providing custom URL-matching function as:
        {
          matcher: (url) => {
            // You can have regex as per your requirement
            if (url.length === 1 && url[0].path.match(/^@[\w]+$/gm)) {
              return {
                consumed: url,
                posParams: {
                  username: new UrlSegment(url[0].path.substr(1), {}) // <--- creating UrlSegment by getting rid of @ from url path
                }
              };
            }
        
            return null;
          },
          component: ProfileComponent
        }
    
    • In profile.component.ts file you can read the username as:
        username$!: Observable<string | null>;
        constructor(private activatedRoute: ActivatedRoute) { }
    
        ngOnInit(): void {
          this.username$ = this.activatedRoute.paramMap
            .pipe(
              map((params: ParamMap) => params.get('username'))
            );
        }
    
    • In profile.component.html you can print the username as:
        <p>
            Profile: {{username$ | async}}
        </p>
    
    • Now simply navigate to url /profile/@user123 and you should be able to get user123 as username in ProfileComponent