Dynamic Routes with Angular
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.
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.
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.
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.