Full disclosure: this article was supposed to be about using Route Guards to protect against data loss. But, as with so many well laid plans, it soon became apparent that I was overreaching a bit. The idea was to build upon what we had done in the Keeping Track of Form Changes In Angular tutorial by displaying a dialog to the user if he or she tried to navigate away from the survey page with unsaved changes.

What Is Angular Routing?

Unlike regular web pages, Angular applications are essentially SPAs (Single Page Applications). Therefore, rather than navigate between pages, Angular employs views made up of routes and components to allow navigation and routing between the various components.

Take a closer look at the index.html page in the root of any Angular project and you'll see an app-root tag in the body:

<body>
  <app-root></app-root>
</body>

In fact, the index.html page is nothing more than a host for our application. The real action takes place within the <app-root></app-root> tags. If we then want to navigate between components, that isn't the place to do it, because it is the outlet for our app. We have to add a router outlet within one (or more) of our app components. Ideally, that's inside of our app.component.html file because that's the "home page" of our application. Angular 11 provides a powerful router that allows you to map browser routes to components. So let's see how we can add routing to our demo from the Keeping Track of Form Changes In Angular tutorial.

Here's what the Navbar looks like with the Home component that we'll be creating next:

angular navbar

Creating the Survey and Home Components

To get a feel for routing, you really need at least two components. Once of the advantages of building on the Keeping Track of Form Changes In Angular demo is that we already have the Survey component. The only issue is that it's in the AppComponent. It should be in its own subfolder. The easiest way to do that is to generate it using the handy-dandy Angular-CLI and then copy over the code from the AppComponent.

The command to generate the Survey component is:

ng g c survey

Likewise for the Home Component:

ng g c home

Here are the new components in the Explorer pane of VS Code:

angular components

Generating the Routing Module

As the name suggests the Routing Module is where we'll define the routes for the application. The command to create it is:

$ ng g m app-routing --flat

The --flat option tells the CLI to generate a file without a subfolder. This way the app-routing.module.ts file will be created in the src/app folder at the same level as the app.module.ts file.

Now, open up the new app-routing.module.ts file and create a constant named "routes". It will contain two objects - one for each route. We'll then pass the routes array to the RouterModule.forRoot() method. Here's what the finished module should look like:

import { NgModule } from "@angular/core";
import { Routes, RouterModule } from "@angular/router";
import { HomeComponent } from "./home/home.component";
import { SurveyComponent } from "./survey/survey.component";

const routes: Routes = [
  { path: "", component: HomeComponent },
  { path: "survey", component: SurveyComponent }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule {}

Finally, add the HomeComponent and SurveyComponent to our AppModule declarations. We also need to import the AppRoutingModule:

import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { AppComponent } from "./app.component";
import { MaterialModule } from "./shared/modules/material/material.module";
import { FormsModule } from "@angular/forms";
import { AppRoutingModule } from "./app-routing.module";
import { HomeComponent } from "./home/home.component";
import { SurveyComponent } from "./survey/survey.component";

@NgModule({
  declarations: [AppComponent, HomeComponent, SurveyComponent],
  imports: [
    BrowserModule,
    MaterialModule,
    FormsModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}

Sprucing Up the AppComponent

As the Home Page, the AppComponent tends to be the perfect place to include a navbar (Navigation Toolbar) with links to various components. Angular Material include the mat-toolbar component for just such an occasion. We'll put the router-outlet below it so that links will change the component:

<mat-toolbar color="primary">
    <a [routerLink]="['/']">Home</a>  
    <a [routerLink]="['/survey']">Survey</a>
</mat-toolbar>
  
<div class="container">
   <router-outlet></router-outlet>
</div>

Don't forget to import the MatToolbarModule from "@angular/material/toolbar" inside the MaterialModule:

import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { MatIconModule } from "@angular/material/icon";
import { MatButtonToggleModule } from "@angular/material/button-toggle";
import { MatInputModule } from '@angular/material/input';
import { MatButtonModule } from '@angular/material/button';
import { MatToolbarModule } from "@angular/material/toolbar";

const materialModules = [
  MatIconModule, 
  MatButtonToggleModule,
  MatInputModule,
  MatButtonModule,
  MatToolbarModule
];

@NgModule({
  declarations: [],
  imports: [CommonModule, ...materialModules],
  exports: [...materialModules]
})
export class MaterialModule {}

Conclusion

As always, there's a demo of today's project on Codesandbox.io. Here's a screenshot of the Survey component:

angular survey component

Now that we've got the routing in place, we can move on to using Route Guards to protect against data loss in the next instalment.


Rob Gravelle resides in Ottawa, Canada, and has been an IT guru for over 20 years. In that time, Rob has built systems for intelligence-related organizations such as Canada Border Services and various commercial businesses. In his spare time, Rob has become an accomplished music artist with several CDs and digital releases to his credit.






This article was originally published on February 25, 2021