Denys Vuika's Blog

Dynamic Routes with Angular

February 21, 2018

In this article, I am going to show you an excellent Angular Router feature related to dynamic route population. It can be handy both for projects and unit testing.

Preparing the project

First, let’s create a minimal project scaffold using the following Angular CLI commands:

ng new medium-dynamic-routes --routing
cd medium-dynamic-routes

Next, generate components for a Home and NotFound routes:

ng g component home --module=app
ng g component not-found --module=app

The Home component is going to be our landing page. We display NotFound component for all the missing content.

To set the initial set of routes, modify the app-routing.module.ts file and add the following entries to the Routes collection:

const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: '**', component: NotFoundComponent },
];

I also suggest replacing the content of the main application template app.component.html with a list of links you are going to test. For the moment it is only the Home link, but we are going to extend it shortly.

<ul>
  <li><a [routerLink]="home">Home</a></li>
</ul>

<router-outlet></router-outlet>

If you run the application now with the ng serve --open command, you should see the “home works!” label on the main page. That means the default route works as expected, and shows us the auto-generated by Angular CLI content.

By default, the application runs at the http://localhost:4200/ address. Try adding navigating to some “missing” address, like http://localhost:4200/about. You should now see the content of the NotFound component. Try multiple addresses to ensure you always end up seeing the same NotFound content.

At this point, we got the minimal application to start experimenting with routes.

Registering routes

Now we are going to create two routes dynamically, and let the application know about them at runtime, without recompiling and restarting.

Let’s create two more components that are going to back our dynamic routes with the next commands:

ng g component page1 --module=app
ng g component page2 --module=app

To simplify the process of testing, we are going to generate the list of available links automatically. Go to the main application component controller app.component.ts and add the following property:

links: Array<{ text: string, path: string }> = [];

The links property is going to hold information about our links. To turn that into the hyperlinks we need the text of the link and the underlying route path.

Next, update the component template to display a dynamic list at the bottom of the static one like in the example below:

<ul>
  <li><a [routerLink]="home">Home</a></li>

  <li *ngFor="let link of links">
    <a [routerLink]="link.path">{{ link.text }}</a>
  </li>
</ul>

<router-outlet></router-outlet>

The property of our interest is Router.config that holds information about known routes. You can populate it from the component constructor or any class method similar to the following:

this.router.config.unshift(
  { path: 'page1', component: Page1Component },
  { path: 'page2', component: Page2Component }
);

Note that for many scenarios, including ours, it is essential to use Array.prototype.unshift function to fill the collection of routes, instead of or the Array.prototype.push.

If you remember, one of the routes in the initial collection is handling all the “missing” routes and displays the NotFound content on the page. Usually, it is the last route in the list and serves as a fallback value. That also means that any new routes added below the ** one are not going to get discovered at runtime. That is why we use unshift to prepend the collection, rather than append it with the push.

Also, to display it on the main page we fill the “links” collection like in the next code snippet:

this.links.push(
  { text: 'page1', path: 'page1' },
  { text: 'page2', path: 'page2' }
);

If you run the application now, there should be three links on the main page: Home, page1 and page2. Try clicking all of them to ensure you can navigate to both static and dynamic routes.

Congratulations, you just got the simple route generation up and running!

You can use this approach for scenarios, which require new routes based on conditions, or completely different components for the same route. That should also help with unit testing, as you can populate route collection on the fly before or during the test run.

You can find full source code for the article in the following repository: https://gitlab.com/DenysVuika/medium-dynamic-routes.

Buy Me A Coffee