Cory Rylan

My name is , Google Developer Expert, Speaker, Software Developer. Building Design Systems and Web Components.

Follow @coryrylan
Angular

Introduction to Angular Routing

Cory Rylan

- 6 minutes

Updated

This article has been updated to the latest version Angular 17 and tested with Angular 16. The content is likely still applicable for all Angular 2 + versions.

Angular brings many improved modules to the Angular ecosystem including a new router called the Component Router. The Component Router is a highly configurable and feature packed router. Features included are standard view routing, nested child routes, named routes, and route parameters. This post we will cover standard routing, route parameters and nested child routes. With these basics we can build a great navigation experience for users that is easy to reason about.

Basic Routing

So now lets take a look at what our first rendered view will look like.

We will start with single app component that has two routes. We will have a home view and a about view. Lets take a look at these two components first.

import { Component } from '@angular/core';

@Component({
selector: 'app-home',
template: `
<h2>Home</h2>
`

})
export class Home {}

@Component({
selector: 'app-about',
template: `
<h2>About</h2>
`

})
export class About {}

So we can see that our two components are very simple just displaying some text. Now lets look at our app component and see how we can use the new Router to route between these two components.

import { Component } from '@angular/core';

@Component({
selector: 'demo-app',
template: `
<a [routerLink]="['/']">Home</a>
<a [routerLink]="['/about']">About</a>
<div class="outer-outlet">
<router-outlet></router-outlet>
</div>
`

})
export class AppComponent {}

So lets walk through our app component step by step and see what this code is doing.

@Component({
selector: 'demo-app',
template: `
<a [routerLink]="['/']">Home</a>
<a [routerLink]="['/about']">About</a>
<div class="outer-outlet">
<router-outlet></router-outlet>
</div>
`

})

So the first part is the [routerLink]. This directive generates our link based on the route path. The second part is the router-outlet, this is the location where Angular will insert the component we want to route to on the view. Next lets take a look at our route config file app.routes.ts.

import { Routes } from '@angular/router';

import { AboutComponent } from 'app/about.component';
import { HomeComponent } from 'app/home.component';

export const routes: Routes = [
{ path: '', component: HomeComponent }
{ path: 'about', component: AboutComponent }
];

Our route config defines all the routes in our application. The first route is our default home route. The second one is our AboutComponent. The path value is the path that we referenced in our template. We export our routes to be added to our App Module.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';

import { routes } from './app.routes';
import { AppComponent } from './app.component';
import { AboutComponent } from './about.component';
import { HomeComponent } from './home.component';

@NgModule({
imports: [BrowserModule, FormsModule, RouterModule.forRoot(routes)],
declarations: [AboutComponent, HomeComponent, AppComponent],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}

Our AppModule is where we create a new @NgModule. A NgModule is a way to bundle components, services and pipes into a single module for Angular to consume. So we will register all of our components to our AppModule then boostrap the module like below.

import { browserDynamicPlatform } from '@angular/platform-browser-dynamic';

import { AppModule } from './app.module';

browserDynamicPlatform().bootstrapModule(AppModule);

Now that our routes are registered we have our standard routing working. Next lets look at nested routes.

Nested Child Routes

Child/Nested routing is a powerful new feature in the new Angular router. We can think of our application as a tree structure, components nested in more components. We can think the same way with our routes and URLs.

So we have the following routes, / and /about. Maybe our about page is extensive and there are a couple of different views we would like to display as well. The URLs would look something like /about and /about/item. The first route would be the default about page but the more route would offer another view with more details.

So lets take a look at what that looks like rendered out.

So as above we can see the About view has its own router-outlet highlighted in blue. The about view also has its own links that navigate between two nested about child components. We can think of this as a tree structure.

Example of Route Tree in Angular

So lets take a look at our About components.

import { Component } from '@angular/core';

@Component({
selector: 'about-home',
template: `
<h3>About Home</h3>
`

})
export class AboutHomeComponent {}

@Component({
selector: 'about-item',
template: `
<h3>About Item</h3>
`

})
export class AboutItemComponent {}

@Component({
selector: 'app-about',
template: `
<h2>About</h2>
<a [routerLink]="['/about']">Home</a>
<a [routerLink]="['/about/item']">Item</a>
<div class="inner-outlet">
<router-outlet></router-outlet>
</div>
`

})
export class AboutComponent {}

So our About template looks very similar to the App component template. Our about component has two child routes, about/ and about/item These pull in two simple components that just display the rendered text above. Notice our route paths start at the root of the about component. The rendered URLs would be /about/ and /about/item. Note remember to add our newly created components to the declarations in our AppModule. Lets now take a look at the updated route config.

import { Routes } from '@angular/router';

import { AboutComponent, AboutHomeComponent, AboutItemComponent } from 'app/about.component';
import { HomeComponent } from 'app/home.component';

export const routes: Routes = [
{ path: '', component: HomeComponent }
{
path: 'about',
component: AboutComponent,
children: [
{ path: '', component: AboutHomeComponent }, // url: about/
{ path: 'item', component: AboutItemComponent } // url: about/item
]
}
];

Notice our path in our About component is now relative for all the child components. Next we will learn how to dynamically change data in our component via route parameters.

Route Parameters

Building on top of our demo app we are now going to add a component that takes in a route parameter. Route parameters allow us to pass values in our url to our component so we can dynamically change our view content. So in our example we will have a route that can take an id and then display it on our AboutItemComponent component. So lets take a look at what the rendered output would be.

Our URLs would be the following: /about/, /about/item/1, and /about/item 2. We can swap out any number in our URL and our item component can pull that value out and display it in the view. Let's take a look at the code for the root about component.

@Component({
selector: 'app-about',
template: `
<h2>About</h2>
<a [routerLink]="['/about']">Home</a>
<a [routerLink]="['/about/item', 1]">Item 1</a>
<a [routerLink]="['/about/item', 2]">Item 2</a>
<div class="inner-outlet">
<router-outlet></router-outlet>
</div>
`

})
export class AboutComponent {}

So the first part in our about template our new [routerLink]'s have a second parameter of the id value ex: ['/about/item', 2]. This allows us to pass in parameters to the router. For now we are just passing in a number. Now lets take a look at the updated route config.

export const routes: Routes = [
{ path: '', component: HomeComponent }
{
path: 'about',
component: AboutComponent,
children: [
{ path: '', component: AboutHomeComponent },
{ path: 'item/:id', component: AboutItemComponent }
]
}
];

Now taking a look at the item route we now have 'item/:id' the : denotes that this is a route parameter and the r outer should get the value in the URL. So now lets take a look at the AboutItemComponent and see how we can get the id from the URL.

import { ActivatedRoute } from '@angular/router';

@Component({
selector: 'about-item',
template: `
<h3>About Item Id: </h3>
`

})
export class AboutItemComponent {
id: any;
paramsSub: any;

constructor(private activatedRoute: ActivatedRoute) {}

ngOnInit() {
this.paramsSub = this.activatedRoute.params.subscribe(
params => (this.id = parseInt(params['id'], 10))
);
}

ngOnDestroy() {
this.paramsSub.unsubscribe();
}
}

We import the ActivatedRoute class and inject it into our component. The parameters are wrapped in an Observable that will push the current route parameter value whenever the parameter is updated. We subscribe for any changes. When a new value is received we set the value to a property on our template. We could just as easily taken this value as an ID to retrieve some data from a API. We capture the subscription in a property so when the component is destroyed we unsubscribe preventing any memory leaks.

Using Observables to get route params works well when the component persists on the same screen without having to be destroyed and recreated each time. If you are certain your component will be destroyed before a new parameter is updated you can use the snapshot api option documented here.

So now lets take a look at our diagram of our application's routes.

Example of Route Tree in Angular with Route Parameters

Recap

So we learned how to do basic routing between components, child/nested routing and route parameters. With these features mastered you can quickly build large scalable Angular apps in no time. As the new Release Candidate router is documented I will update this post accordingly. Take a look at full working demo in the link below.

View Demo Code   
Twitter Facebook LinkedIn Email
 

No spam. Short occasional updates on Web Development articles, videos, and new courses in your inbox.

Related Posts

Angular

Creating Dynamic Tables in Angular

Learn how to easily create HTML tables in Angular from dynamic data sources.

Read Article
Web Components

Reusable Component Patterns - Default Slots

Learn about how to use default slots in Web Components for a more flexible API design.

Read Article
Web Components

Reusable Component Anti-Patterns - Semantic Obfuscation

Learn about UI Component API design and one of the common anti-patterns, Semantic Obfuscation.

Read Article