1

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?

3 Answers 3

2

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
Sign up to request clarification or add additional context in comments.

1 Comment

This solution worked with a little tweak, since I wanted to do /@user123, not /profile/@user123. Also, I added the hyphen in the regex. I will post the modified solution, but I accepted your answer. Thanks
1

The solution provided by Siddhant is excellent, but I wanted /@user123 instead of /profile/@user123, so I tweaked it a little.

app-routing.module.ts

{
  matcher: (url) => {
    if (url.length === 1 && url[0].path.match(/^@[\w.\-]+$/gm)) { // <--- added a hyphen and a dot, since \w only does [a-zA-Z0-9_]
      return {
        consumed: url,
        posParams: {
          username: new UrlSegment(url[0].path.substr(1), {}) // <--- creating UrlSegment by getting rid of @ from url path
        }
      };
    }
    return null;
  },
  loadChildren: () => import('./modules/profile/profile.module').then(m => m.ProfileModule)
},

profile.routing.module.ts

{
  path: '',
  component: ProfileComponent
},

profile.component.ts

ngOnInit(): void {
  this.activatedRoute.paramMap.subscribe(paramMap => {
    this.userService.getUser(paramMap.get('username')).subscribe(res => {
      if (res) {
        this.user = res;
      } else {
        this.router.navigate([Utils.ARTICLE_NOT_FOUND_URL]);
      }
    });
  });
}

Comments

0

I am adding another answer, since I also needed to use the @user123/edit path, but it didn't work with the original solution. So here is how to do it:

app-routing.module.ts

 {
    matcher: (url) => {
      console.log(url);
      if (url[0].path.match(/^@[\w.\-]+$/gm)) { <-- removed check for url length
        return {
          consumed: url.slice(0, 1), <-- return the rest of the URL instead of the whole URL (this routing rule should only consume @user123 and return the rest of the URL, which is /edit)
          posParams: {
            username: new UrlSegment(url[0].path.substr(1), {}) // <--- creating UrlSegment by getting rid of @ from url path
          }
        };
      }
      return null;
    },
    loadChildren: () => import('./modules/profile/profile.module').then(m => m.ProfileModule)
  },

profile.routing.module.ts

{
    path: '',
    component: ProfileComponent
  },
  {
    path: 'edit',
    component: EditProfileComponent
  },

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.