javascriptangularangular4-router

Allowing Angular 4 routes to pass special characters in URL


What i am trying to do

I am trying to create a route in my application where i want to allow the admin to type in the url as

http://localhost:4200/#/start/referral_code=jk

And then get the value for referral_code i.e jk inside the component.

In my routes i have defined the route as

{ path: 'start/:referral_code', component: StartPageComponent },    

What i am trying to achieve is that when the admin enters the above provided URL then the value for the variable referral_code should be received inside the specified component StartPageComponent. I have added the following inside ngOnInit() as follows

this.activatedRoute.params.subscribe((params: any) => {
      if (params) {
        let refCode = params.referral_code;
        console.log(refCode);
      }
    });

What Happens Actually

As soon as i type in the above URL the part after = is removed along with the = and the resulting url is changed to

http://localhost:4200/#/start/referral_code

and inside the component the console.log(refCode); displays the string referral_code rather than the value for the referral_code i.e jk.

Limitation

I cannot use QueryParams like http://localhost:4200/#/start?referral_code=jk neither I can change the url http://localhost:4200/#/start/referral_code=jk

I appreciate any help.


Solution

  • You can override Angular's DefaultUrlSerializer.

    import {BrowserModule} from '@angular/platform-browser';
    import {Injectable, NgModule} from '@angular/core';
    
    import {AppComponent} from './app.component';
    import {DefaultUrlSerializer, RouterModule, Routes, UrlSegment, UrlSerializer, UrlTree} from '@angular/router';
    import {RouteTestComponent} from './route-test/route-test.component';
    
    @Injectable()
    export class CustomUrlSerializer implements UrlSerializer {
      /** Parses a url into a {@link UrlTree} */
      private defaultSerializer: DefaultUrlSerializer = new DefaultUrlSerializer();
    
      /** Parses a url into a {@link UrlTree} */
      parse(url: string): UrlTree {
    
        // This is the custom patch where you'll collect segment containing '='
        const lastSlashIndex = url.lastIndexOf('/'), equalSignIndex = url.indexOf('=', lastSlashIndex);
        if (equalSignIndex > -1) { // url contians '=', apply patch
          const keyValArr = url.substr(lastSlashIndex + 1).split('=');
          const urlTree = this.defaultSerializer.parse(url);
    
          // Once you have serialized urlTree, you have two options to capture '=' part
          // Method 1. replace desired segment with whole "key=val" as segment
          urlTree.root.children['primary'].segments.forEach((segment: UrlSegment) => {
            if (segment.path === keyValArr[0]) {
              segment.path = keyValArr.join('='); // Suggestion: you can use other unique set of characters here too e.g. '$$$'
            }
          });
    
          // Method 2. This is the second method, insert a custom query parameter
          // urlTree.queryParams[keyValArr[0]] = keyValArr[1];
          return urlTree;
        } else {
          // return as usual
          return this.defaultSerializer.parse(url);
        }
      }
    
      /** Converts a {@link UrlTree} into a url */
      serialize(tree: UrlTree): string {
        return this.defaultSerializer.serialize(tree);
      }
    }
    
    const appRoutes: Routes = [
      {
        path: 'start/:referral_code',
        component: RouteTestComponent
      }
    ];
    
    @NgModule({
      declarations: [
        AppComponent,
        RouteTestComponent
      ],
      imports: [
        RouterModule.forRoot(appRoutes, {useHash: true}),
        BrowserModule
      ],
      providers: [
        {
          provide: UrlSerializer,
          useClass: CustomUrlSerializer
        }
      ],
      bootstrap: [AppComponent]
    })
    export class AppModule {
    }
    

    Inside the component

    this.route.params.subscribe(params => {
       console.log(params['referral_code']); // prints: referral_code=jk
    });
    // url http://localhost:4200/#/start/referral_code=jk will be changed to http://localhost:4200/#/start/referral_code%3Djk
    

    Or if you prefer Method 2 above, use:

    this.route.queryParams.subscribe(queryParams => {
      console.log(queryParams['referral_code']); // prints: jk
    });
    // url http://localhost:4200/#/start/referral_code=jk will be changed to http://localhost:4200/#/start/referral_code?referral_code=jk