Search code examples
javascriptangulartypescriptangular4-router

How to config routing Angular4 router


Problem: I am configuring routes for my application. I want to have my url like https://localhost:4200/hero=id where id will be what ever user selects from Heroscomponent.This is not working for me.

if I try below url whose path is /hero/:id as per angular docs it works phonemically.

https://localhost:4200/hero/:id

Can some please provide me a solution to this problem.

This is my route config file where

 const appRoutes: Routes = [
  { path: 'hero', component: HeroesComponent },
  {path: 'hero{=:id}', component: HeroDetailComponent},
  {
    path: 'home',
    redirectTo: '/hero',
    data: { title: 'Heroes List' }
  },{
    path: 'student',
    component: AppTable
  },{
    path: 'video',
    component: VideoTagComponent
  },{ path: '',
    redirectTo: '/hero',
    pathMatch: 'full'
  }
  // { path: '**', component: PageNotFoundComponent }
];

Below is my HeroesComponent file where i am routing to path = "/hero="+id

import { Component } from '@angular/core';
import { Router } from '@angular/router';
import {Hero} from './hero';


const HEROES: Hero[] = [
  { id: 11, name: 'Mr. Nice' },
  { id: 12, name: 'Narco' },
  { id: 13, name: 'Bombasto' },
  { id: 14, name: 'Celeritas' },
  { id: 15, name: 'Magneta' },
  { id: 16, name: 'RubberMan' },
  { id: 17, name: 'Dynama' },
  { id: 18, name: 'Dr IQ' },
  { id: 19, name: 'Magma' },
  { id: 20, name: 'Tornado' }
];

@Component({
    selector: 'my-heroes',
    templateUrl: './heroes.html',
    styleUrls: ['./app.component.css']
})

export class HeroesComponent {
    hero = HEROES;
    path:string;
    selectedHero: Hero;

    constructor(private router: Router){}        

    onSelect(hero: Hero): void {
      this.selectedHero = hero;
      this.path = "/hero=" +this.selectedHero.id.toString();
      this.router.navigate([this.path]);
    }

    // gotoDetail(): void {
    // }
}

This is the error i am getting in the browser console.
core.es5.js:1020 ERROR Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'hero%3D13' Error: Cannot match any routes. URL Segment: 'hero%3D13'**strong text**


Solution

  • I found a solution to this problem.

    Because Angular don't support this.. So, we can create a CustomUrlSerializer

       import { UrlSerializer, UrlTree, DefaultUrlSerializer } from '@angular/router';
    
    export class CustomUrlSerializer implements UrlSerializer {
        public parse(url: any): UrlTree {
            let _serializer = new DefaultUrlSerializer();
            return _serializer.parse(url.replace('=', '%3D'));
        }
    
        public serialize(tree: UrlTree): any {     
            let _serializer = new DefaultUrlSerializer();
            let path = _serializer.serialize(tree);
            // use regex to replace as per the requirement.
            return path.replace(/%3D/g, '=');
        }
    }
    

    import this module where you are bootstrapping your AppComponent

    import { CustomUrlSerializer } from 'file path';
    
    @NgModule({
      bootstrap: [ AppComponent ],
      imports: [
      ],
      providers: [
        { provide: UrlSerializer, useClass: CustomUrlSerializer},
    
      ]
    })
    

    In Your routing module create a matcher for mapping the route.

    export const ROUTES: Routes = [
      { matcher: pathMatcher, component: ComponetName},
      ];
    
    const KEYWORD = /hero=([^?]*)/;
    
    
    export function pathMatcher(url: UrlSegment[], group: UrlSegmentGroup, route: Route): any {
        if (url.length >= 1) {
            const [part1] = url
            if (part1.path.startsWith('hero')) {
                const [,keyword] = KEYWORD.exec(part1.path) || ['',''];
                let consumedUrl: UrlSegment[] = [];
                consumedUrl.push(url[0]);
                return {
                    consumed: consumedUrl,
                    posParams: { //The parameters if any you want to pass to ur component
                        heroId: new UrlSegment(keyword,{})
                    }
                }
            }
        }
        return null
    }
    

    Now, In your component you can fetch the heroId by using

    this.route.params.subscribe((params)=>{
              this.data = params['heroId'];
          })
    

    where route is instance of ActivatedRoute