There comes a point in our journey to take a way in getting to a destination, in Angular we do this using routing. In this article, we will explore Angular Routing concept and explore the ways to make component routable and ways to navigate.
Angular as a framework provide inbuilt component routing support. So, no need to hunt down any NPM based routing library. It provides extensive routing support covering many use cases related to component routing. In this article we will continue with the same Notesy App where we left last time with Angular Journey: Part 2 - Bindings, Directives, Components, Services this article.
We will head in this direction:
Before even talking we can straight head toward creating components. These components will be routable unlike any other component those are treated as child components. There is no difference while creating a routable component. Before creating such component will first create a folder called "pages". Under "src/app/pages" folder run these commands:
ng g c home
ng g c about
ng g c not-found
Here, we have created a folder called "pages", we also have a folder called "component". We can simply put the components those are routable to the "pages" folder otherwise will put the components in the "components" folder.
NOTE: This is not something coming from Angular guide or convention, instead it's just a logical separation of components based on their nature. Such similar concept can be seen in the Next.js as well.
The next step is to configure our routes. To do this we need to go to the "app-routing.module.ts" file. Open the file:
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
const routes: Routes = [];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Here, we have a code from previous article. We can see the routes array is empty, lets fill it up with routes related to home, about and not-found components.
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: '**', component: NotFoundComponent }
];
Here, we have added 3 routes, the first one is an empty path which points to the HomeComponent, the second one is a dedicated path called as "about" which points to the AboutComponent. Lastly, we have a wildcard route, in case no routes matches then the NotFoundComponent will be displayed to the user.
Here, the sequencing of the routes is very important, the wildcard route must not be placed as the first route, if that happens then we wont be able to navigate to any other component as all path will points to the wildcard path only.
Till this point we won't be able to see any change in our Notesy App. In order to display the routed components, we will be needing a "router-outlet", which is a directive that helps to display the routed components based on the changes in the URL path. We will add this router-outlet to the app.component and will move the main content to home component and will also add some content to About and Not Found components as well.
Currently, out app.component looks like this:
<app-header></app-header>
<div class="container my-5">
<div class="row">
<div class="col">
<app-form></app-form>
<app-list></app-list>
<app-empty></app-empty>
</div>
</div>
</div>
<app-footer></app-footer>
Let us remove the main content, which is the form, list and empty of our Notesy App and add the router-outlet instead:
<app-header></app-header>
<div class="container my-5">
<div class="row">
<div class="col">
<router-outlet></router-outlet>
</div>
</div>
</div>
<app-footer></app-footer>
Move the main content to the home component:
<app-form></app-form>
<app-list></app-list>
<app-empty></app-empty>
Add below content to the about component:
<div>
<h4 class="mb-4"><i class="bi bi-heart-fill text-danger"></i> About</h4>
<p class="lead fw-semibold">
Unleash your inner Shakespeare or just jot down your grocery list – our
notesy is here to fulfill all your note-taking fantasies.
</p>
<p>
It is like having a personal assistant who is fantastic at remembering stuff
but does not need a paycheck.
</p>
<p>
From dear diary confessions to important meeting reminders, we have got a
note template for every mood swing and milestone.
</p>
<p>
So, let your thoughts flow like a river of creativity, and let our app be
the dam that holds them all together. With us, every note is a masterpiece
waiting to happen!
</p>
<p>
Angular: <a href="https://angular.dev/" target="_blank">angular.dev</a>.
</p>
<p>Notesy Version: <span class="badge bg-secondary">1.0.0</span></p>
</div>
Add below content to the not-found component:
<div class="p-5 text-center bg-body-secondary rounded">
<div class="m-5">
<h1 class="display-1 fw-bolder text-success">404</h1>
<p>The page you are looking for is no where to be found!</p>
</div>
</div>
If you now visit the pages by typing their respective routes in the Browser's URL then you will see corresponding component loaded on the screen.
Cool, but this is not it, the user should be able to navigate to these pages through some nav links. Let us now create the nav links for these pages. Will create a Navbar component to have these links placed. Will add this navbar component to the "src/app/components" folder as this will be a not routed component directly added as a child to the app component.
ng g c navbar
Go to the navbar component and add below code:
<div class="d-flex justify-content-center mt-4">
<a
href="/"
class="btn btn-light mx-1 d-flex align-items-center"
>
<i class="bi bi-house-fill text-success me-2 fs-6"></i> Home
</a>
<a
href="/about"
class="btn btn-light mx-1 d-flex align-items-center"
>
<i class="bi bi-heart-fill text-danger me-2 fs-6"></i> About
</a>
</div>
Here, we have added the anchor tags for the navigation pointing to these pages.
But when you click on these links, they will cause a page post back as they are the vanilla HTML anchor tags. Angular treats them as an entire page refresh instead of a component navigation. To prevent vanilla navigation Angular provided "routerLink" directive. Let us just modify these anchor tags:
<a [routerLink]="['/']">...</a>
<a [routerLink]="['/about']">...</a>
Here, we have added the property binding of the "routerLink" directive to the anchor tag and provided the path in array format.
If we want to show the current active navbar in different color (simply by changing the CSS class) then we can do this with another directive called "routerLinkActive":
<a
[routerLink]="['/']"
routerLinkActive="bg-body-secondary">...</a>
<a
[routerLink]="['/about']"
routerLinkActive="bg-body-secondary">...</a>
There is a small glitch still remaining, when we go to the "/about" page the home page still shows in active color. This is because the active check is happening on partial match instead of exact match of the route. To perform exact matching of the path for active links we can use "routerLinkActiveOptions" directive:
<a
[routerLink]="['/']"
routerLinkActive="bg-body-secondary"
[routerLinkActiveOptions]="{ exact: true }">...</a>
<a
[routerLink]="['/about']"
routerLinkActive="bg-body-secondary"
[routerLinkActiveOptions]="{ exact: true }">...</a>
Here, the object provided to the "routerLinkActiveOptions" has property called exact which we are setting explicitly to true.
There will time comes when we want to perform the navigation from the TypeScript code of the component instead from the template. In order to do so we can use the "navigate" method of the "Router" service.
import { Router } from '@angular/router';
@Component({...})
export class FooterComponent {
constructor(private router: Router) {}
gotoAbout() {
this.router.navigate(['/about']);
}
}
Here, we have called the navigate method of the Router service and provided the path where we want to navigate. Notice that we have provided the same array-based path to the navigate method. Simply call the gotoAbout method in the template button:
<button (click)="gotoAbout()">Notesy 1.0.0/button>
December 31, 2020
October 19, 2020
March 02, 2022