RafaelTSCS
RafaelTSCS

Reputation: 1314

Is there a way to name a route in Angular 7?

I was wondering if there is a way to name my routes in Angular7 so I could just call [routerLink]="myRouteName" instead of [routerLink]="/my/route/path".

If so, how can I achieve this?

Upvotes: 23

Views: 23472

Answers (6)

SlimenTN
SlimenTN

Reputation: 3564

This is old but crazy how Angular does not yet support this out of the box, when application gets bigger and there are a lot of URLs with a lot of slashes in it, it will be very hard very to remember it.

I've managed to create a pipe that support routes naming and it supports route params and query params, this is the code:

import { Pipe, PipeTransform } from '@angular/core';
import { Router, Route } from '@angular/router';
import {isUndefined} from "util";

@Pipe({
  name: 'path'
})
export class RoutingPipe implements PipeTransform {
  private _path: string = null;
  constructor(
    private _router: Router
  ){}

  transform(_route_name: any, params?: {}): any {
    this._path = null;
    this.findPath(this._router.config, _route_name);
    if(this._path == null) throw new Error('No path found for name "'+_route_name+'"!');
    if(params){
      for (let k in params) {
        if (params.hasOwnProperty(k)) {
           this._path = this._path.replace(`:${k}`, params[k]);
        }
      }
    }
    return this._path;
  }

  /**
   * navigate to component by route name
   *
   * @param name route name
   * @param params route params if exist
   */
  navigate(name: string, params?: {}){
    this._router.navigate([this.transform(name, params)]);
  }

  /**
   * Find route's full path by name
   *
   * @param config routes
   * @param name route name
   * @param parent
   */
  findPath(config: Route[], name: String, parent?: string) {
    parent = parent || '';

    for (let i = 0; i < config.length; i++) {
      const route: Route = config[i];
      const path = parent + '/' + route.path;
      if (route.children) {
        // this._path = null;
        const currentPath = route.path ? parent + '/' + route.path : parent;
        this.findPath(route.children, name, currentPath);
      }else{
        if(!isUndefined(route.data) && (<any>route.data).name == name){
          this._path = path;
        }
      }
    }
  }

}

declare it in the routing.ts file:

{ path: 'users/:id/edit', component: UserComponent, data: { name: 'edit_user' }}

You can use it like this in your html file:

<a [routerLink]="'edit_user'|path:35">Some link</a>

also inside your component.ts as a service (make sure to inject it in the constructor)

editUser(){
    let userID = // look for user id
    this._router.navigate('edit_user', {id: userID});
}

Upvotes: 1

PreQL
PreQL

Reputation: 358

I managed to do this like this (bonus if someone can tell me how to remove the Array loop):

custom-route.interface.ts -- this is to add name to our route object


export interface ICustomRoute extends Route {

  name?: string;

}

In routing.module.ts (or wherever you have stored your routes):

const routes: ICustomRoute[] = [
  { path: 'some/random/page1', component: TestComponent, name: 'page1'  },
  { path: 'some/random/page2', component: Test2Component, name: 'page2'  },
  { path: 'page3', component: Test3Component, name: 'page3'  },
];

Now the name is being passed into your routing module so now you have to catch the name and handle it. You can do this in a number of ways, I ended up using a directive (I saw @Safron mentioned a pipe as well)

named-routerlink.directive.ts

@Directive({
  selector: 'a[namedRouterLink]'
})
export class NamedRouterLinkDirective extends RouterLinkWithHref{
  @Input('namedRouterLink')

  set namedRouterLink(val: any) {
    const selectedRoute = this.myRoute.config.filter( x => x['name'] == val)[0];
    this.routerLink = "/" + selectedRoute['path']
  };

  constructor(router: Router, route: ActivatedRoute, locationStrategy: LocationStrategy, private myRoute: Router){
    super(router, route, locationStrategy)
  }

}

And then obviously use like this:

 <a namedRouterLink="page1">Page 1</a>

Pipe Version:

@Pipe({name: 'getRoute' })
export class RoutePipe implements PipeTransform {

  constructor(private router: Router){}

  transform(routeName: string): string {
    const selectedRoute = this.router.config.filter( x => x['name'] == routeName)[0];
    return "/" + selectedRoute['path']
  }

}

Pipe Example:

 <a namedRouterLink="{{ 'page1' | getRoute }}">Page 1</a>

Upvotes: 7

Ashish Ranjan
Ashish Ranjan

Reputation: 12960

Considering you want to configure the routes names while you are creating the route configuration.

Lets leverage routes' data property to add names to routes. (A small extra data in every route should not affect any performance).

But first, let's create a class which conatains a static property for holding route names and their actual paths.

export class RouteNames {
  public static routeNamesObject = {}
}

Now in your routing component where you have defined the routes, let's have it like:

const routes: Routes = [
  {path: "hello/:id", component: HelloComponent, data: {routeName: "Hello1"}},
  {path: "hello", component: HelloComponent, data: { routeName: "Hello2" }}
]

Just after this variable initialization set the RouteNames class's static prop

routes.forEach((eachRoute) => {
  RouteNames.routeNamesObject[eachRoute.data.routeName] = eachRoute.path;    // now all route paths are added to this prop
})

Make a public variable in your component to access the static class

Like in app.component.ts: (You don't need injection)

public routeNames = RouteNames;

Then the app.component.html will be something like:

<button [routerLink]="routeNames.routeNamesObject['Hello2']">Click to Navigate to Hello</button>

Upvotes: 19

Rohit.007
Rohit.007

Reputation: 3502

You can use constant file for that so that it can be reusable in other components too.

export const ROUTE_URL = {
    myRouteName: '/my/route/path',
};

As many as you have.

then use that constant on .TS and use it in the view.

View:

<a [routerLink]="routerUrls.myRouteName"></a>

.TS:

public routerUrls= ROUTE_URL;

Even on your route file

 { path: 'xyz', loadChildren:  ROUTE_URL.myRouteName},

Upvotes: 4

dev-dan
dev-dan

Reputation: 6293

In your class

public routeName = '/customRoute/myExample'

Then in your template

[routerLink]="routeName"

This should pull that value through, i think thats what you are asking for. This will only work if the customRoute is actually a valid route name you have made.

Upvotes: 3

Mile Mijatović
Mile Mijatović

Reputation: 3177

<a [routerLink]="routerLinkVariable"></a>

So this variable (routerLinkVariable) could be defined inside your class and it should have a value like below

export class myComponent {

     public routerLinkVariable = "/my/route/path"; // the value of the variable is string!
}

Upvotes: 7

Related Questions