Learn how to use the Angular Router to add routes and links that render the content we want when we navigate to the routes.
Angular is a framework that lets us create interactive web frontends for users. It lets us write single-page frontend apps that can let us show different things according to the URL we go to.
It does this by providing a routing library that lets us map URLs to components. Then when we go to a URL, we see the component that we want to render.
In this article, we will look at how to use the Angular Router to add routes and links that render the content we want when we navigate to the routes.
Angular Router
Angular apps are mostly single-page apps, but we want to render multiple pages. Therefore, we need client-side routing in our app.
Angular comes with its own client-side routing library to let us render the component we want according to the URL we are going to. We can add links that have the route URLs as the destination so that when we click on the link, we will see the content we expect.
To use it, first we have to import the AppRouting
module that we will create that includes the routing code.
We write:
app.module.ts
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
import { FooComponent } from "./foo/foo.component";
import { BarComponent } from "./bar/bar.component";
@NgModule({
declarations: [AppComponent, FooComponent, BarComponent],
imports: [BrowserModule, AppRoutingModule],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
to import the AppRoutingModule
component so that we can use routing in AppModule
.
We also add FooComponent
and BarComponent
to register the two components in AppModule
so they can be rendered.
Then we run:
ng g component Foo
and
ng g component Bar
to create the Foo
and Bar
components which will be our route components.
Next, we map URLs to the route components we just created in app-routing.module.ts
by writing:
app-routing.module.ts
import { NgModule } from "@angular/core";
import { Routes, RouterModule } from "@angular/router";
import { BarComponent } from "./bar/bar.component";
import { FooComponent } from "./foo/foo.component";
const routes: Routes = [
{ path: "foo", component: FooComponent },
{ path: "bar", component: BarComponent },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
The path
property is the URL path relative to the base URL. And the component
property is set to the component that will be rendered when we go to the URL.
We add RouterModule.forRoot(routes)
to the imports
array to register the routes.
And we add RouterModule
to the exports
array so we can import RouterModule
along with AppRoutingModule
so that Angular will use the routes on this module when we import it in another module.
We can also add redirects easily with Angular’s router. For instance, we update app-routing.module.ts
to the following:
app-routing.module.ts
import { NgModule } from "@angular/core";
import { Routes, RouterModule } from "@angular/router";
import { BarComponent } from "./bar/bar.component";
import { FooComponent } from "./foo/foo.component";
import { PageNotFoundComponent } from "./page-not-found/page-not-found.component";
const routes: Routes = [
{ path: "foo", component: FooComponent },
{ path: "bar", component: BarComponent },
{ path: "", redirectTo: "/foo", pathMatch: "full" },
{ path: "**", component: PageNotFoundComponent },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
We added { path: "", redirectTo: "/foo", pathMatch: "full" },
to redirect /
to /foo
. The pathMatch
property is set to 'full'
so that the full path has to match before the redirect takes
place.
Also, we added { path: "**", component: PageNotFoundComponent }
to add a wildcard route that is rendered
when no routes on the list above it are matched.
Therefore, the PageNotFoundComponent
’s contents is rendered when we navigate to any URL other than /foo
, /bar
, or /
.
Also, we can set the title for each route easily. All we have to do is add the title
property to the route objects.
For instance, we replace with we have in app-routing.module.ts
with:
app-routing.module.ts
import { NgModule } from "@angular/core";
import { Routes, RouterModule } from "@angular/router";
import { BarComponent } from "./bar/bar.component";
import { FooComponent } from "./foo/foo.component";
import { PageNotFoundComponent } from "./page-not-found/page-not-found.component";
const routes: Routes = [
{ path: "foo", title: "Foo", component: FooComponent },
{ path: "bar", title: "Bar", component: BarComponent },
{ path: "", redirectTo: "/foo", pathMatch: "full" },
{ path: "**", component: PageNotFoundComponent },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
We just set the title
property to the value we want and they will be displayed as the title of each route in the browser.
To make the title dynamic, we create a class that extends the TitleStrategy
class.
For instance, we replace with we have in app-routing.module.ts
with:
app-routing.module.ts
import { Injectable, NgModule } from "@angular/core";
import { Title } from "@angular/platform-browser";
import {
Routes,
RouterModule,
TitleStrategy,
RouterStateSnapshot,
} from "@angular/router";
import { BarComponent } from "./bar/bar.component";
import { FooComponent } from "./foo/foo.component";
import { PageNotFoundComponent } from "./page-not-found/page-not-found.component";
const routes: Routes = [
{ path: "foo", title: "Foo", component: FooComponent },
{ path: "bar", title: "Bar", component: BarComponent },
{ path: "", redirectTo: "/foo", pathMatch: "full" },
{ path: "**", component: PageNotFoundComponent },
];
@Injectable()
export class TemplatePageTitleStrategy extends TitleStrategy {
constructor(private readonly title: Title) {
super();
}
override updateTitle(routerState: RouterStateSnapshot) {
const title = this.buildTitle(routerState);
if (title !== undefined) {
this.title.setTitle(`App | ${title}`);
}
}
}
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
providers: [{ provide: TitleStrategy, useClass: TemplatePageTitleStrategy }],
})
export class AppRoutingModule {}
to add the TemplatePageTitleStrategy
class into app-routing.module.ts
file. We make it injectable with the injectable
decorator.
In the class, we add the updateTitle
method which overrides the default title with our own text. We use buildTitle
to return the title
property value of the route. Then we call this.title.setTitle
with the title we want, which includes the value of title
that we got from buildTitle
.
As a result, we see that the title is App | Foo
when we go to /foo
and is App | Bar
when we go to /bar
.
Angular Router Links
Now that we have the route components added and registered, we can add some links that let us reach the pages.
In app.component.html
, we replace the existing content with:
app.component.html
<nav>
<ul>
<li>
<a
routerLink="/foo"
routerLinkActive="active"
ariaCurrentWhenActive="page"
>Foo</a
>
</li>
<li>
<a
routerLink="/bar"
routerLinkActive="active"
ariaCurrentWhenActive="page"
>Bar</a
>
</li>
</ul>
</nav>
<router-outlet></router-outlet>
We add two a
elements that are rendered as links. We want them to render components that we registered, so we set the routerLink
attribute to /foo
and /bar
respectively.
The router-outlet
component lets us render the content for the component that we mapped the URL to. Therefore, we see the links on the top of the page with the content for the Foo
and Bar
routes below it depending
on the URL we are on.
This will let us see the content of the Foo
and Bar
components respectively since we mapped /foo
to the Foo
component and /bar
to the Bar
component with:
const routes: Routes = [
{ path: "foo", component: FooComponent },
{ path: "bar", component: BarComponent },
];
routerLinkActive
is set to the active
class so the styles for the active
class will be rendered when the link’s URL matches the URL of the page we are on.
To add some styles for the active
class, we write:
app.component.css
.active {
font-weight: bold;
}
to make the link text bold when the link’s URL matches the URL of the page we are on.
If we are on /foo
, then Foo
is highlighted. And if we are on /bar
, then Bar
is highlighted.
Conclusion
Angular lets us write single-page frontend apps that can let us show different things according to the URL we go to. It does this by providing a routing library that lets us map URLs to components.
Then when we go to a URL, we see the component that we want to render. We can use Angular Router to register routes by mapping URLs to route components.
Also, we can set up redirects and add wildcard routes that render a component with content that we want to show when nothing else on the route list matches the URLs listed.
And we can add router links easily so we can add links that render the components we want by adding a few attributes to regular HTML a
elements.
The router-outlet
component is used to render the route component contents.