89

I have a quick question. I'm currently looking through https://angular.io/docs/ts/latest/api/router/Router-class.html but I was wondering, in my Angular2's main.ts I have my routes defined thus:

@Routes([
    { path: '/', component: HomeComponent },
    { path: '/about-me', component: AboutMeComponent },
    { path: '/food', component: FoodComponent },
    { path: '/photos', component: PhotosComponent },
    { path: '/technology', component: TechnologyComponent },
    { path: '/blog', component:Blogomponent },
])

Now in a component elsewhere I import the Router class. In my component (or the component template) I would like to loop through all my routes defined or just be able to access them. Is there a built in way to do this? Like some function that returns an object array? Here is a crude idea of what I want...

@Component({
    selector: 'ms-navigation',
    templateUrl: 'src/navigation/navigation.template.html',
    directives: [ ROUTER_DIRECTIVES ]
})

export class NavigationComponent {
    constructor(private router:Router) {   
        // what can I do here to get an array of all my routes?
        console.log(router.routes); ????
    }
}
2
  • This user factored it out of the decorator. Commented Jun 1, 2016 at 13:49
  • So I can access an array of the routes doing this.router.config (no browser errors), however, this throws the following typescript error in terminal ~ error TS2341: Property 'config' is private and only accessible within class 'Router'. Now if only we can debug this error or find some other clues to help us get there ... Commented Aug 1, 2016 at 23:44

13 Answers 13

64

Update 2024 July: Since this answer was long time ago, I've not caught up for all newer versions, there is a aux to this answer by Adrian for newer versions with lazy-loading. Please refer that too for newer versions of Angular.


Here is a better version which will list all possible routes (fixed according to comments):

import { Router, Route } from "@angular/router";

constructor(private router: Router) { }

ngOnInit() {
  this.printpath('', this.router.config);
}

printpath(parent: string, config: Route[]) {
  for (let i = 0; i < config.length; i++) {
    const route = config[i];
    console.log(parent + '/' + route.path);
    if (route.children) {
      const currentPath = route.path ? `${parent}/${route.path}` : parent;
      this.printpath(currentPath, route.children);
    }
  }
}
Sign up to request clarification or add additional context in comments.

8 Comments

This is useful but it's a little misleading. To get "all possible routes", you need to remove the && r.path in the last if statement. I had child routes which were in a module with a default empty string route which caused all the child routes to be skipped because they were nested under the empty string route.
In Angular5, I only get the top-level routes with this one, because children are undefined. How would I get all possible routes (including children) as opposed to all loaded routes?
Tested on Angular 9. Works okay apart from where you have lazy loaded routes (tested using the promise syntax i.e. loadChildren: () => import('./pathToModule/lazy.module').then(m => m.LazyModule)). In that case I think it would be ideal to add another condition check if ('_loadedConfig' in route) {} in which you can access child routes from route['_loadedConfig'].routes
does not work @rey_coder route['_loadedConfig'] returns undefined. _loadedConfig is not part of the public API
Yes, @THEAMAZING and I captured that in the comment....i.e it doesn't work if the route is lazy loaded. thus the 'loadedConfig' property check condition to ensure value is defined. Unlesss on your end it also doesnt work for all routes.
|
48

Apparently there is a very compact way to do it:

constructor(private router: Router) {}

ngOnInit() {
  console.log('configured routes: ', this.router.config);
}

2 Comments

This only works module-wise. If you are having more than one module in your application, you will only get the routes according to the module you are executing the commans above.
Doesn't work when using lazy-loading
16

If you only need the route paths as strings, you can find them by iterating over your Router object's config array.

    for (var i = 0; i < this.router.config.length; i++) {
        var routePath:string = this.router.config[i].path;
        console.log(routePath);
    }

1 Comment

This only shows the top level routes. Anand Rockzz's answer is much better
13

I am using this comp. to get all routes in angular 9

import { Compiler, Component, Injector, OnInit } from '@angular/core';
import { Route, Router } from '@angular/router';

@Component({
  templateUrl: './sitemap.component.html'
})
export class SiteMapComponent implements OnInit {

  public urls: string[] = [];
  constructor(private _router: Router, private compiler: Compiler, private injector: Injector) {

  }

  ngOnInit() {
    this._router.config.forEach(i => {
      this.getPaths(i);
    })
  }

  getPaths(route: Route, parent: string = '') {
    if (route.redirectTo) {
      return;
    }
    if (route.children) {
      route.children.forEach(i => {
        this.getPaths(i, parent + route.path);
      });
    }
    else if (route.loadChildren) {
      (<any>this._router).configLoader.load(this.injector, route).subscribe(i => {
        i.routes.forEach(j => {
          this.getPaths(j, parent + route.path)
        });
      });
    }
    else if (route.path != null) {
      this.setPath(route.path, parent);
    }
  }
  setPath(path, parent) {
    let fullPath: string;
    if (path != null) {
      if (parent) {
        fullPath = `/${parent}/${path}`;
      }
      else {
        fullPath = `/${path}`
      }
    }
    this.urls.push(fullPath)
  }
}

Update Angular 14: configLoader.load

(<any>this._router).configLoader.loadChildren

Update Angular 17: configLoader.loadChildren

(<any>this._router).navigationTransitions.configLoader.loadChildren

Comments

7

This comes as an extension to @Anand Rockzz's answer.

Was written for Angular 6.0 and list all possible routes including the lazy ones (https://angular.io/guide/lazy-loading-ngmodules):

UPDATED

As @Daniel B mentioned:

[...] this no longer works with Angular 8.0

import { Route } from '@angular/router';
import { LoadedRouterConfig } from '@angular/router/src/config';

printPaths(parent: string, routes: Route[]) {
    const getFullPath = (path?: string) => {
        if (path) {
            return parent + '/' + path;
        }

        return parent;
    };

    for (let i = 0; i < routes.length; i++) {
        const route = routes[i];
        const fullPath = getFullPath(route.path);

        console.log(parent + '/' + route.path, route.component);

        if (route.children /*&& route.children.length > 0*/) {
            this.printPaths(fullPath, route.children);
        }

        if (route.loadChildren && route.loadChildren.length > 0) {
            var routerConfig = <LoadedRouterConfig>(<any>route)['_loadedConfig'];
            if (routerConfig) {
                this.printPaths(fullPath, routerConfig.routes);
            }
        }
    }
}

14 Comments

Forgot to mention that this should not be used in production. The core issue might be that the code is being minified and there will no longer be a variable called _loadedConfig.
Just a comment to inform people that this no longer works with Angular 8.0.
What are the alternatives now in Angular 8?
Maybe this is no longer working in Angular 8 due to the fact that LoadedRouterConfig is "moved" to an untyped file @angular/router/bundles/router.umd.js. Will update the code after I'll get a working solution.
@AdrianPaul it's been a year, any luck?
|
3

For @angular version 2.00 I was able to find a list of the children through the routeConfig property.

Here is an example of my component. Note, I'm accessing the children via the 'parent' property as the component is actually one of the children as I'm rendering it in the child router-outlet.

import { Component } from '@angular/core';
import {Route, ActivatedRoute, Router} from "@angular/router";

@Component({
    selector: 'list',
    template: require('./list.component.html')
})
export class ListComponent {
    children = new Array<RouteLink>();

    constructor(private router: Router, private activatedRoute: ActivatedRoute) {
        for (let child of activatedRoute.parent.routeConfig.children) {
            if (child.path && child.data["breadcrumb"]) {
                this.children.push(new RouteLink(child.path, child.data["breadcrumb"]));
            }
        }
    }
}

export class RouteLink {
    constructor(private path: string, private name: string) {  }
}

1 Comment

does not work..
2

I’ve created a util function based on the answer of @OMANSAK. Tested with Angular 12 and lazy loaded modules.

import { Injector } from '@angular/core';
import { Router, Route } from '@angular/router';

const routerUrls: string[] = [];

async function getPaths(router: Router, injector: Injector, route: Route, parent: string = ''): Promise<void> {
   if (route.redirectTo) {
       return;
   }
   if (route.children) {
       for (const childRoute of route.children) {
           await getPaths(router, injector, childRoute, parent + route.path);
       }
   } else if (route.loadChildren) {
       const lazyConfig = await router['configLoader'].load(injector, route).toPromise();
       for (const childRoute of lazyConfig.routes) {
           await getPaths(router, injector, childRoute, parent + route.path);
       }
   } else if (route.path !== null) {
       if (route.path !== '') {
           routerUrls.push(parent ? `/${parent}/${route.path}` : `/${route.path}`);
       } else {
           routerUrls.push(parent ? `/${parent}` : '');
       }
   }
}

/**
 * Returns routes of the app via the Angular Router.
 *
 * Important: The fallback route in the app module (path: "**")
 * has to be the last element in your top level app-routing-module.
 *
 * @param router Angular Router
 * @param injector Angular Injector
 * @returns Routes of the app
*/
export async function getAllPaths(router: Router, injector: Injector): Promise<string[]> {
   const topLevelRoutes = router.config.slice(
       0,
       router.config.findIndex((route) => route.path === '**') ?? router.config.length - 1
   );
   for (const i of topLevelRoutes) {
       await getPaths(router, injector, i);
   }
   return routerUrls;
}

Comments

1

From Angular 9+, you can look at a component that has a Router injected, via the browser console:

window.ng.getComponent(document.querySelector('app-employee-overview')).router.config[0].children

Comments

0

You run into issues using this solution if you have Lazy routes. I made a simple bash command to show the routing information:

cd /path/to/app 
for r in $(find src -name "*.routes.ts"); do 
  echo $r; grep "path:\|component:\|loadChildren:" $r; 
done

2 Comments

Great! Now, how did you run it in your Angular app?
this is a build script, not what you are looking for. @rey_coder
0

A small update for @Vasco's answer above for Angular 14

import { Injector } from '@angular/core';
import { Router, Route } from '@angular/router';

let routerUrls: { path: string; component: any }[] = [];

async function getRoutes(
    router: Router,
    injector: Injector,
    route: Route,
    parent: string = ''
): Promise<void> {
    if (route.redirectTo) {
        return;
    }
    if (route.children) {
        for (const childRoute of route.children) {
            await getRoutes(
                router,
                injector,
                childRoute,
                parent ? `${parent}/${route.path}` : route.path
            );
        }
    } else if (route.loadChildren) {
        const lazyConfig = await router['configLoader'].loadChildren(injector, route).toPromise();
        for (const childRoute of lazyConfig.routes) {
            await getRoutes(router, injector, childRoute, parent + route.path);
        }
    } else if (route.path !== null) {
        if (route.path !== '') {
            routerUrls.push({
                path: parent ? `/${parent}/${route.path}` : `/${route.path}`,
                component: route.component,
            });
        } else {
            routerUrls.push({ path: parent ? `/${parent}` : '', component: route.component });
        }
    }
}

/**
 * Returns routes of the app via the Angular Router.
 *
 * Important: The fallback route in the app module (path: "**")
 * has to be the last element in your top level app-routing-module.
 *
 * @param router Angular Router
 * @param injector Angular Injector
 * @returns Routes of the app
 */
export async function getAllRoutes(
    router: Router,
    injector: Injector
): Promise<{ path: string; component: any }[]> {
    routerUrls = [];
    const topLevelRoutes = router.config.slice(
        0,
        router.config.findIndex((route) => route.path === '**') ?? router.config.length - 1
    );
    for (const i of topLevelRoutes) {
        await getRoutes(router, injector, i);
    }
    return routerUrls;
}

Comments

0

For reference: getting routes when using lazy components is difficult in run time, but thanks to the popularity of frameworks like Scully for the jamsstack we can now use guess-parser to list our routes during build time.

This is a build script, so it may or may not be what you want.

parseAngularRoutes(tsconfig: string) - Extracts the routes of an Angular application. As arguments the function accepts path to the tsconfig.json file of the project. https://www.npmjs.com/package/guess-parser

Here's a concept to hook this into the build;

Install the dev dep. npm i guess-parser --save-dev. Add a file and add something along the lines of this:

var guess = require('.\\node_modules\\guess-parser\\dist\\guess-parser\\index.js');
console.log(guess.parseAngularRoutes('.\tsconfig.json')); // Output for now, but you could save this as json in your /dist/assets folder and serve it

Then run ng build and node output-routes.js and see the results roll in after some time:

[
  ...
  {
    path: '/general/overview',
    lazy: true,
    modulePath: '[REDACTED]\\src\\app\\modules\\general\\general.module.ts',
    parentModulePath: '[REDACTED]\\src\\app\\app.module.ts'
  },
  {
    path: '/general/products',
    lazy: true,
    modulePath: '[REDACTED]\\src\\app\\modules\\general\\general.module.ts',
    parentModulePath: '[REDACTED]\\src\\app\\app.module.ts'
  },
  ...
]

This could be hooked up in your build process after building. This could also be hooked into file watchers, see: Hook into angular-cli build watch

Comments

0
  1. Turn on preloading of all modules

provideRouter(appRoutes, withPreloading(PreloadAllModules))

  1. Replace your app.component.ts with this
import { ChangeDetectionStrategy, Component, inject, OnInit } from '@angular/core';
import { Route, Router, RouterModule } from '@angular/router';
import { trim, uniq } from 'lodash';

@Component({
  standalone: true,
  selector: 'app-root',
  imports: [RouterModule],
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.less'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent implements OnInit {
  result: string[] = [];
  readonly #router = inject(Router);

  ngOnInit() {
    setTimeout(() => {
      this.collectRoutes('', this.#router.config);
      for (const route of uniq(this.result.map((r) => trim(r, '/*')))) {
        console.log(route);
      }
    }, 5000);
  }

  collectRoutes(parent: string, config: Route[]) {
    for (const route of config) {
      this.result.push(`your_app_domain${parent}/${route.path}`);
      if (route.children) {
        const currentPath = route.path ? `${parent}/${route.path}` : parent;
        this.collectRoutes(currentPath, route.children);
      }
      if ((route as any)._loadedRoutes) {
        const currentPath = route.path ? `${parent}/${route.path}` : parent;
        this.collectRoutes(currentPath, (route as any)._loadedRoutes);
      }
    }
  }
}
  1. Modify as you need, run your app and wait 5 seconds

Comments

-1

if you want to look at the available route by importing into a component.

assign your routes to a constant like below

const appRoutes: Routes = [
    {
        path: 'asd',
        component: asdComponent
    },
    {
        path: 'ar',
        component: arComponent
    }
];

export const routing = RouterModule.forRoot(appRoutes);

here you will be able to export the routes

import the const routing

import { routing }        from './app.routing';
export class AppComponent {
   route=routing;
   /// route.providers is an array which internally contains the list of routes provided
   console.log(route.providers);
}

this is just to find the available routes. not recommendable to implement logic based on this

1 Comment

#1 do not import appRoutes, use dependency injection with Router. Also providers is not part of the Routes.

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.