Angular routing with a prefix and a parameter in the route

I am currently working on implementing the user profile page. While it would be easy to use the

/profile/user123 path by simply updating:

app-routing.module

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

profile-routing.module

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

my aim is to create a more unique URL structure like /@user123.

Despite my efforts, I haven't been successful in achieving this using the following approach:

app-routing.module

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

profile-routing.module

{
  path: '',
  component: ProfileComponent
},

Unfortunately, this method did not work as expected.

One potential solution that comes to mind is utilizing a Guard to check for the '@' prefix and redirecting to the /not-found page if it's not present.

Do you have any suggestions on how to achieve this routing in a more "Angular" way?

Answer №1

To achieve the desired outcome, utilize a custom route matcher.

  • app-routing.module.ts
    {
      path: 'profile',
      loadChildren: () => import('./modules/profile/profile.module').then(m => m.ProfileModule)
    },
  • In profile-routing.module.ts, define a route with a custom URL-matching function as follows:
    {
      matcher: (url) => {
        // Define regex pattern accordingly
        if (url.length === 1 && url[0].path.match(/^@[\w]+$/gm)) {
          return {
            consumed: url,
            posParams: {
              username: new UrlSegment(url[0].path.substr(1), {}) // <--- Create UrlSegment by removing @ from url path
            }
          };
        }
    
        return null;
      },
      component: ProfileComponent
    }
  • In profile.component.ts, access the username parameter as demonstrated below:
    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, display the username using the following code:
    <p>
        Profile: {{username$ | async}}
    </p>
  • To see the result, navigate to the URL /profile/@user123 and observe user123 as the username in ProfileComponent

Answer №2

The response given by Siddhant is remarkable, however, I preferred using /@user123 over /profile/@user123, so I made some adjustments.

app-routing.module.ts

{
  matcher: (url) => {
    if (url.length === 1 && url[0].path.match(/^@[\w.\-]+$/gm)) { // <--- included a hyphen and a dot to widen the scope
      return {
        consumed: url,
        posParams: {
          username: new UrlSegment(url[0].path.substr(1), {}) // <--- modified to remove @ 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]);
      }
    });
  });
}

Answer №3

After encountering an issue with utilizing the @user123/edit path in my project, I found a workaround that solved the problem. Here is the updated solution:

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), <-- modify to only consume @user123 and return the rest of the URL (/edit)
          posParams: {
            username: new UrlSegment(url[0].path.substr(1), {}) // <--- creating UrlSegment by removing @ from the 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
  },

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to showcase images at random in Angular?

I am trying to display a random array of images in the UI, but I'm encountering an error with innerHTML when using the code below in TypeScript. randomPic(){ this.randomNum= Math.floor(Math.random() * this.myPix.length); console.log(this.rando ...

Finding the value of an item within a JSON sub-array based on the most recent date that falls within a specified timeframe

I am currently developing a billing application using Angular. The items array that I am working with is structured like this (showing only one item here):- items: [{ _id: "5ee2298f59ce2e1747cb5539" createdAt: "2020-06-11T ...

Can ES6 class getters, setters, and private properties be utilized in TypeScript with an interface?

I'm currently using TypeScript and trying to figure out how to implement an interface in a class that utilizes ES6 getters and setters. Is it even possible? When I use the code below, errors are highlighted in the class. For instance: (property) S ...

Should services be directly referenced in HTML templates when using Angular 2?

Is it advisable to reference the service directly in the template by using this code: [disabled]="stateService.selectedClient == null || stateService.currentStep == 1" In my view, this approach does not appear to be a good practice. I would prefer to ha ...

The data type 'Observable<any>' cannot be assigned to the type 'StoresSummaryResults'. The property 'Data' is not present in the 'Observable<any>' type

As a newcomer to using the Observable with Angular 2, I am facing an issue where my structure is not receiving the results despite being able to validate the response from my REST API. Below is the data class in Typescript that I have: import { RESTResul ...

Tips for adjusting collisions between models using three.js and oimo.js

I am currently working on implementing collision with an object using three.js by importing a model and then creating a body in Oimo to represent it. My problem arises from the fact that the center of the model does not align with the center of the object ...

Challenges with Angular 2 navigation paths

I'm currently facing a routing issue in my Angular 2 project. The app is quite small, featuring a PageNotFoundComponent, a HomeComponent for the index page, and an admin section. The admin section consists of a main AdminComponent, an AdminDashboardC ...

What is the best method for sharing templates and logic in VUE?

Two separate components with shared logic and template, making it appear as though one is extending the other. Think of Drop and Pick components in this manner: // pick.js import Vue from 'vue' import Component from 'vue-class-component& ...

Angular's counterpart to IWebProxy

When using C#, I am able to: public static IWebProxy GetWebProxy() { var proxyUrl = Environment.GetEnvironmentVariable("HTTPS_PROXY"); if (!string.IsNullOrEmpty(proxyUrl)) { var proxy = new WebProxy { Address = new Ur ...

When using mongoose.save(), the data is not stored successfully

I spent 5 hours trying to solve this problem but couldn't figure out what's wrong in the file -routes/users.ts, The line ""targetUser.token = token" is working, so console.log(targetUser) shows the updated user data. However, targetU ...

Tips for successfully passing an Observable identifier to mergeMap

Monitoring the outputs of a list of observables with mergeMap is straightforward, as shown in this example code snippet: export class TestClass { test() { const observableA = of(1, 2, 3); const observableB = of(7, 3, 6); const observableC = ...

Utilizing optional chaining with function parameters

When dealing with a function f: (X => Y) | undefined that may be undefined, and x: X is defined, we can utilize the optional chaining operator ?. to apply f to x: f?.(x) // This is fine even if `f` is undefined However, if f: X => Y is defi ...

Guide to making a Typescript interface by combining elements from two separate interfaces without utilizing inheritance

Programming Language: Typescript I am looking to combine the properties of two interfaces as the value of an indexable-type within a third interface. Interface 1: export interface Employee { id: string name: string } Interface 2: export interfa ...

Steps for enabling a function to return an undefined type

After extensive review, I have discovered that TypeScript has numerous hidden nuances, which make it less strict and accurate. I prefer to utilize 'undefined' as the return type for functions because it accurately reflects the reality of the sit ...

The animation in ThreeJs encounters context issues within Angular 2

I am trying to incorporate ThreeJs into my Angular 2 project. I have successfully rendered a scene with a simple cube, but I ran into an issue when using the animate() function. Here is the code snippet: import { OnInit, Component } from '@angular/co ...

What is the best way to utilize "exports" in package.json for TypeScript and nested submodules?

Looking to leverage the relatively new "exports" functionality in Node.js/package.json for the following setup: "exports": { ".": "./dist/index.js", "./foo": "./dist/path/to/foo.js" } so that ...

Cross-Platform: Varied functionalities in disabled input fields (avoiding any direct replication)

My input HTML field is disabled, but I've noticed that in some browsers (such as Chrome, Edge, Internet Explorer, and Opera), it's still possible to select and copy the text. However, in Firefox, this functionality does not work. To test this yo ...

Passing data between a component and a service in Angular 6

Looking to incorporate a loading or spinner image into Angular 6? The spinner should become visible when an HTTP service makes a request and disappear once a response is received. You can integrate the image into a component by using the loading variable: ...

Encountering TS1240 Error When Implementing TypeScript Property Decorators in Code Execution

I'm in the midst of a TypeScript project where I am utilizing property decorators to impose validation on class properties. Below is a simplified version of the code I am working with: Please note: Experimental decorators are enabled for this project ...

Is it possible for node modules to access and utilize protractor parameters?

Is it feasible for a node module to access a protractor parameter? I am in need of defining a parameter in my protractor conf.js file and then running a specific section of the shared node module js file across 5 projects. For instance, in my conf.js: ...