npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@ngrdt/router

v0.0.80

Published

Main use for this package is to define routes and their parameters in one place in app. It is recommended to define special `routes` module in every app using `@ngrdt/router` where all `RdtRoute` objects are defined using `RdtRouteBuilder`. Individual app

Readme

@ngrdt/router

Main use for this package is to define routes and their parameters in one place in app. It is recommended to define special routes module in every app using @ngrdt/router where all RdtRoute objects are defined using RdtRouteBuilder. Individual application modules then import these objects, define Angular routes and provide implementation details such as which component is rendered, state, guards, etc.

This approach ensures that each route is defined exactly once and can be easily edited if necessary. @ngrdt/router also provides set of useful tools to help you with common routing tasks.

Instalation

npm install @ngrdt/router

Basic usage

Application routes file

Create special nx library (not NgModule) for instance @example-app/routes. In this library you will create file called routes.ts and in it individual RdtRoute objects like so:

export const DASHBOARD_ITEM_ROUTE = new RdtRouteBuilder()
  .setName('Dashboard item')
  .setPath(':id')
  .setParam('id', 'number')
  .build();

export const DASHBOARD_ROUTE = new RdtRouteBuilder()
  .setName('Dashboard')
  .setPath('dashboard')
  .setChildren(DASHBOARD_ITEM_ROUTE)
  .build();

export const SETTINGS_ROUTE = new RdtRouteBuilder()
  .setName('Settings')
  .setPath('settings')
  .setCanBeEntered(() => 
    inject(ExampleAppPermissionService).hasPermission('SETTINGS_ACCESS')
  )
  .build();

This file should only contain imports to interfaces used by RdtRouteBuilder as template parameter. No component, ngModule or guards such as CanActivateFn should be imported here. This approach will save you later headache with circular dependency.

RdtRouterService needs to be aware of all routes defined therefore you must provide it in your ApplicationConfig like so:

import { RDT_ROUTES_PROVIDER, RdtRoute } from '@ngrdt/router';
import * as ALL_ROUTES_OBJ from './rdt-routes';
const ALL_ROUTES = Object.values(ALL_ROUTES_OBJ) as RdtRoute[];

export const appConfig: ApplicationConfig = {
  providers: [
    {
      provide: RDT_ROUTES_PROVIDER,
      useValue: ALL_ROUTES,
    },
  ]
}

Angular routes files

Now you have to bind RdtRoute objects to individual modules, components, states, effects, guards and other implementation details. Instead of defining routes directly you import RdtRoute from @example-app/routes and then define routes.ts like so:

export const routes: Route[] = [
  DASHBOARD_ROUTE.toAngularRoute()
    .setComponent(DashboardComponent)
    .setChildren(
      DASHBOARD_ITEM_ROUTE.toAngularRoute()
        .setComponent(DashboardItemComponent)
        .addCanDeactivate(preventDataLossGuardFn)
        .build()
    )
    .build(),
]

This array is then used as in regular Angular project. Note that child routes must be added as children here as well.

Child routes and parameters

You may nest child routes and also create routes with typed parameters to link them with particular type.

For instance lets say there's a route displaying users which has a child route to display more information about a single user. By providing User type to RdtRouteBuilder and defining types of parameters we can use RdtRoute object to parse path to extract parameters.

interface User {
  userId: number;
  name: string;
}

export const USER_DETAIL_ROUTE = new RdtRouteBuilder<User>()
  .setName('User detail')
  .setPath(':userId/:name')
  .setParam('userId', 'number')
  .setParam('name', 'string')
  .build();

export const USER_LIST_ROUTE = new RdtRouteBuilder()
  .setName('Users')
  .setPath('users')
  .setChildren(USER_DETAIL_ROUTE)
  .build();

Then we navigate to user detail like so:

const params: Partial<User> = {
  userId: 123,
  name: 'Josef',
};

inject(RdtRouterService).navigate(USER_DETAIL_ROUTE, params);

RdtRouterService is aware of the type so you can use it to parse absolute path into User object. Route knows userId is number so it will parse it. If parameter is missing or is of wrong type, then parseAbsoluteUrl returns null. Return value is a wrapper object with get(route: RdtRoute) method to get parsed parameters of given route or its parents.

const user: User = USER_DETAIL_ROUTE
  .parse('/users/123/Josef')
  .get(USER_DETAIL_ROUTE);

More parameter examples

Static parameters

Imagine your app contains list of users and each user has set of tasks. The routes are defined as follows:

interface User {
  userId: number,
  name: string,
  address: string,
  tasks: Task[]
}

interface Task {
  taskId: number,
  description: string
}


export const TASK_DETAIL_ROUTE = new RdtRouteBuilder<Task>()
  .setName('Task detail')
  .setPath('task/:taskId')
  .setParam('taskId', 'number')
  .build();

export const USER_DETAIL_ROUTE = new RdtRouteBuilder<User>()
  .setName('User detail')
  .setPath(':userId')
  .setParam('userId', 'number')
  .setChildren(TASK_DETAIL_ROUTE)
  .build();

export const USER_LIST_ROUTE = new RdtRouteBuilder()
  .setName('Users')
  .setPath('user')
  .setChildren(USER_DETAIL_ROUTE)
  .build();

This translates into path /user/:userId/task/:taskId for task detail route.

Now inside UserDetailComponent there's a for loop rendering individual tasks and you want to have links to them. You cannot use directly:

<button [rdtRouterLink]="TASK_DETAIL_ROUTE" [params]="task"></button>

Because task does not specify userId. For this you must provide static parameters for every parent route - User for USER_DETAIL_ROUTE in this case:

@Input()
user!: User;

taskRoute!: RdtRoute<Task>;

ngOnInit() {
  this.taskRoute = TASK_DETAIL_ROUTE.withStaticParams(USER_DETAIL_ROUTE, this.user);
}

Method withStaticParams() returns clone of TASK_DETAIL_ROUTE and all of its parent routes while fixing parameters. You can chain calling withStaticParams with itself or other method calls.

<button [rdtRouterLink]="taskRoute" [params]="task"></button>

Ecosystem

RdtRouterLink

RdtRouterLink is equivalent of RouterLink in Angular. It supports basically the same functionality, but adds type safety. RdtRouterLink will be disabled if canBeEntered of its route returns false.

readonly userRoute = USER_DETAIL_ROUTE;
readonly user$ = inject(UserService).getUser$();
<button 
  [rdtRouterLink]="userRoute" 
  [params]="user$ | async"
  target="_blank">
Link to user
</button>

RdtMenu

RdtRoute can be passed directly into RdtMenuItem. If canBeEntered returns false, then the item won't be visible. This is useful to hide items user has no permission for.

Method withStaticParams lets us provide parameters for given RdtRoute, because RdtMenuItem does not accept route parameters.

public getMenuItems(): RdtMenuItem[] {
  const user: Partial<User> = {
    userId: 123,
    name: 'Josef'
  };

  return [
    {
      label: 'All users',
      routerLink: USER_LIST_ROUTE
    },
    {
      label: 'Josef',
      routerLink: USER_DETAIL_ROUTE.withStaticParams(user)
    }
  ];
}

RdtAngularRoute

RdtAngularRoute is a container class for RdtRoute which functionally does two things: verifies that routes were defined correctly and enables you to provide guards, effects, component or module. Don't forget to call build() for it to generate Angular Route.

RdtRouterService

RdtRouterService has similar features as Angular Router.

parseAbsoluteUrl()

Method will parse absolute path, recognize RdtRoute and parse its parameters. If no parameter is provided, then window location is used.

navigateBack()

Will push parent route to navigation stack. Function works anywhere in the app unlike similar Angular-based solution using ActivatedRoute.

Hitting native browser back button will take you back forward. In case you want true back function, use inject(Location).back() which removes from navigation stack, but can potentially take you outside of the app or close browser window.

previousUrl and currentUrl

Cached sync values of previous and current path values. For example /dashboard or /user/123/task/xyz.