BairesDev
  1. Blog
  2. Software Development
  3. Mastering Angular Routing: A Comprehensive Guide
Software Development

Mastering Angular Routing: A Comprehensive Guide

Learn how to master Angular routing with our easy-to-follow tutorial! From basic concepts to advanced techniques, we've got you covered. Start building better web applications today.

BairesDev Editorial Team

By BairesDev Editorial Team

BairesDev is an award-winning nearshore software outsourcing company. Our 4,000+ engineers and specialists are well-versed in 100s of technologies.

13 min read

Featured image

In a fast-paced world, delivering an engaging and responsive user experience is vital. Angular is a widely-used front-end framework developed and maintained by Google. Over the years, Angular gained popularity since its inception due to a vast set of features and robust community support. Routing is a crucial aspect of modern web applications that helps in dynamic user interfaces.

According to the State of JS 2022 survey, Google’s Angular framework had 48.8% usage as the second most popular web framework. Angular offers powerful routing capabilities that make it easy to create complex navigation paths and handle dynamic content.

Without further ado, let’s dig deeper into the Angular router!

Basics of Angular Routing

Routing refers to navigating between different pages or views within a single-page application, a critical feature of Angular development services. In a SPA, the content within the application is loaded dynamically without the need to refresh the page. Angular, as part of its development services, uses the built-in router to handle routing within its applications. The Angular router maps URLs to components. Whenever a user clicks on a link, the router returns the default route mapped to the URL and renders the appropriate app component.

The route configuration is usually defined in the app-routing.module.ts file. Each route has a path that maps to a component. For example, a route for a dashboard page would have path /dashboard and be mapped to DashboardComponent.

The Angular router matches the URL path to the defined routes and loads the associated component into the router outlet. The router outlet acts as a placeholder where the content of the currently selected component is displayed.

Angular routing consists of several key components that work together to enable navigation within the application. These components include:

Component Description
RouterModule Provides necessary directives and services for routing.
Routes These are individual routes that are defined in the application. Each route has a path that is linked to a component.
RouterOutlet This is a directive that is used to define where the routed component should be displayed in the application. It is placed in the app component.
RouterLink It is used to define links that trigger routing within an application.
Router Provides methods for navigating between routes of an application.
ActivatedRoute This is a service that provides information about the currently activated route.

Routing Module

Developers can modularize the routing configuration in an application by using Routing Module. To create a router module you can use the Angular CLI to generate a new module with the routing flag.

The following command is used to generate the new module.

ng generate module app-routing --routing

After creating the Routing Module you need to be imported it into the app module. Next you will have to define the routes for the application by creating a routes array. Every Route object in routes array defines a path and a component to render.

Once the routes are defined you will now have to configure the routes by calling the forRoot() method of the RouterModule. It returns a configured RouterModule, which is to be imported into the app module.

Setting up Angular Routing

Let’s look at implementing an Angular router into a real-world application. Imagine you are building a website for a restaurant that has multiple pages. It has a homepage, a menu page, and a contact page. You want to utilize an Angular router to display appropriate angular components. By doing so the users can navigate between the pages easily.

Prerequisites

To implement routing in Angular successfully, you must have the following:

  • Node.js: The latest version of Node.js on your machine
  • A Code Editor: Any IDE that supports Angular
  • npm: Node Package Manager to install the required dependencies
  • Angular CLI: The latest version which provides Angular core

Create a New Project

Create a new Angular project using the Angular CLI by running the command in your terminal.

ng new restaurant-website

You can now see a package.json file in your project directory, similar to the one below:

Please note that the versions of dependencies are specified in the above file. These were the versions at the time of the creation of this guide.

Implementing Routing Module

In the src app app.module.ts file and import the RouterModule and Routes modules to implement app routing.

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

Now add the RouterModule to the imports array in the @NgModule decorator.

@NgModule({
imports: [
RouterModule.forRoot(routes)
],
...
})

Create a new file called app-routing.module.ts in src app folder and add the following code for route configuration.

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';import { HomeComponent } from './home/home.component';
import { MenuComponent } from './menu/menu.component';
import { ContactComponent } from './contact/contact.component';
export const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'menu', component: MenuComponent },
{ path: 'contact', component: ContactComponent }
];

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

Create three new components for the home page, menu page, and contact page. Run the following commands:

ng generate component home
ng generate component menu
ng generate component contact

In the app.component.html file, add the RouterOutlet component to display the current route’s content.

<router-outlet></router-outlet>

Open the home.component.html file, add the RouterLink directive to create a link to the menu page. This would be the first route when the app loads.

<h2>Abc Restaurant</h2>
<p>Welcome to our restaurant!
We specialize in delicious food and great service.<br />
Come visit us for a meal you won't forget.</p><br />
<a routerLink="/menu">View Our Menu</a>

In the menu.component.html file, add the RouterLink directive to create a link to the contact page.

<h2>Abc Restaurant - Menu</h2>
<p>Here is our menu!</p>
<ul>
<li>Appetizers:
<ul>
<li>Chicken Wings</li>
<li>Mozzarella Sticks</li>
</ul>
</li>
<li>Entrees:
<ul>
<li>Grilled Salmon</li>
<li>Steak and Fries</li>
</ul>
</li>
<li>Desserts:
<ul>
<li>Chocolate Cake</li>
<li>Apple Pie</li>
</ul>
</li>
</ul><br /><a routerLink="/contact">Contact Us</a>

In the contact.component.html file, add the RouterLink directive to create a link to back to the home page.

<h2>Abc Restaurant - Contact</h2>
<p>Address: 123 Main Street<br />
Phone: 555-1234<br />
Email: [email protected]<br />
Hours of operation: Monday-Saturday, 11am-10pm</p><br />
<a routerLink="/">Back to Home</a>

Start the app using the following command ng serve –open and navigate between the home, menu, and contact pages using the links created with RouterLink.

This is how the app would look like in the browser:

Home Page

Menu Page

Contact Page

If you look at the browser address bar, you can see that every page has a different URL path segment.

Advanced Angular Routing Concepts

Let’s look at a few advanced routing concepts in Angular.

1. Nested Routes (Child Routes)

Nested routing allows developers to define a route within a route. The main purpose of this is to create a hierarchical navigation structure that properly shows the hierarchy of multiple components within the application. This makes navigation easier and makes the router configuration more modular.

To configure child routes when creating routes developers need first to define a parent route. This parent route then contains the child routes. They are nested within the parent route using the children property. Let’s look at the example below to see how it’s done.

const routes: Routes = [
{
path: 'products',
component: ProductsComponent,
children: [
{ path: ':id', component: ProductDetailsComponent },
{ path: '', component: ProductListComponent }
]
}
];

2. Route Guards

Route Guards enable developers to control access to routes based on certain conditions. By putting up conditions additional security and unauthorized access is put up on certain routes.

There are three main types of route guards:

  1. canActivate: determines if a route can be activated.
  2. canDeactivate: determines if a route can be deactivated.
  3. canLoad: determines if a route can be lazy loaded.

Let’s look at the example below to see how to implement it.

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router } from '@angular/router';
import { Observable } from 'rxjs';@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private router: Router) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
const isLoggedIn = true; // Check if user is logged in
if (isLoggedIn) {
return true;
} else {
return this.router.parseUrl('/login');
}
}
}

3. Lazy Loading

Lazy loading allows the developers to load modules on demand instead of loading all of them at once. This helps in decreasing the initial load time of the application and therefore loads only the necessary modules at a time.

In order to implement lazy load modules in angular you will need to create a feature module for every feature of the application. Then the routes will be configured with the loadChilden property. Let’s look at an example.

const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'customers', loadChildren: () => import('./customers/customers.module').then(m => m.CustomersModule) },
{ path: 'orders', loadChildren: () => import('./orders/orders.module').then(m => m.OrdersModule) },
{ path: '**', component: PageNotFoundComponent }
];

4. Route Parameters

Route parameters allow the developers to pass data between the components and routes. This enables dynamic navigation by providing context to the component using the parameter.

Route parameters are defined using : syntax in the route path and can be required or optional depending on the need. For example, /products/:id defines a route with a required id parameter.

Developers can use ActivatedRoute to access a route parameter. This provides access to current route and its parameters. Route parameters are stored in the params property of the ActivatedRoute object.

Let’s look at an example.

const routes: Routes = [

{ path: 'products/:id', component: ProductDetailsComponent }
];// ProductDetailsComponent
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-product-details',
templateUrl: './product-details.component.html',
styleUrls: ['./product-details.component.css']
})
export class ProductDetailsComponent implements OnInit {
productId: string;

constructor(private route: ActivatedRoute) { }

ngOnInit() {
this.route.params.subscribe(params => {
this.productId = params['id'];
});
}
}

In the above example, the ProductDetailsComponent accesses the id parameter using the ActivatedRoute service and subscribes to changes using the params observable.

Best Practices for Angular Routing

Here are a few best practices that you should follow:

1. Organizing Routes and Modules

You should separate routing module for every feature module to keep the code organized and easier to maintain. To improve the flow of the application you can group routes which are related to each other. You should also implement lazy loading to load modules on demand. This increased the initial load time of the application. Moreover, it’s important to use a naming convention for your routes that makes them easy to understand and follow. This helps to avoid confusion for both you and other developers who may be working on the project.

2. Handling Route Errors and 404 Pages

You should use the ** wildcard route to catch all routes that do not match. In order to make the user experience more seamless you can also create a custom component to display a 404 page when a route is not found and you can use the Router.navigate() method to redirect the user to the custom 404 page.

3. Improving Performance With Route Preloading

In route preloading you can use the PreloadAllModules strategy. This strategy preloads all modules in the background. Another strategy that you can use is SelectivePreloadingStrategy. It only preloads specific modules that are likely to be used therefore reducing the initial load time. Moreover, in order to prevent preloading of modules that the user does not have access to you can use the canLoad guard.

By following these above best practices you can create an organized and optimized Angular application.

Testing Angular Router

Unit testing Angular routes means that you have to test the the routing configuration and verify that the route is navigating properly. Integration Testing includes the testing of the behavior of the components during navigation.

RouterTestingModule is used to implement unit testing. Let’s look at an example implementation.

import { RouterTestingModule } from '@angular/router/testing';
import { TestBed } from '@angular/core/testing';
import { Router } from '@angular/router';
import { AppComponent } from './app.component';describe('AppComponent', () => {
let router: Router;
let fixture;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule.withRoutes([])],
declarations: [AppComponent]
});

fixture = TestBed.createComponent(AppComponent);
router = TestBed.inject(Router);
});

it('should navigate to the home route', () => {
spyOn(router, 'navigateByUrl');

fixture.detectChanges();

expect(router.navigateByUrl).toHaveBeenCalledWith('/');
});
});

To integration test your routes, you can use the Angular RouterTestingModule and the RouterOutlet component to verify that the expected components are loaded when navigating to a specific route. Let’s look at the implementation.

import { RouterTestingModule } from '@angular/router/testing';
import { TestBed } from '@angular/core/testing';
import { Router } from '@angular/router';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { MenuComponent } from './menu/menu.component';
import { ContactComponent } from './contact/contact.component';describe('AppComponent', () => {
let router: Router;
let fixture;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule.withRoutes([
{ path: '', component: HomeComponent },
{ path: 'menu', component: MenuComponent },
{ path: 'contact', component: ContactComponent }
])
],
declarations: [
AppComponent,
HomeComponent,
MenuComponent,
ContactComponent
]
});

fixture = TestBed.createComponent(AppComponent);
router = TestBed.inject(Router);
});

it('should load the home component when navigating to the home route', () => {
fixture.detectChanges();

router.navigate(['']);

fixture.detectChanges();

const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('app-home')).toBeTruthy();
});

it('should load the menu component when navigating to the menu route', () => {
fixture.detectChanges();

router.navigate(['/menu']);

fixture.detectChanges();

const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('app-menu')).toBeTruthy();
});

it('should load the contact component when navigating to the contact route', () => {
fixture.detectChanges();

router.navigate(['/contact']);

fixture.detectChanges();

const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('app-contact')).toBeTruthy();
});
});

Conclusion

Mastering Angular routing is an essential skill for any modern Angular web developer, including those involved in outsourced Angular software development. With client-side routing being the norm, it’s critical to understand how to create dynamic and efficient routing in your applications. Angular routing provides a flexible and powerful toolset for all sorts of applications and use cases, making it particularly beneficial for outsourced Angular software development projects.

There are plenty of resources available for further learning, including official Angular documentation and online tutorials. Its important to hire a company which offers high quality Angular development services for your Angular project. Before doing so you can it is also important to know whether React or Vue is the best fit for your project instead of Angular since every project has different needs.

If you enjoyed this article, check out:

Key Questions

How can I handle redirects and aliasing in Angular routing?
To setup redirects in Angular routing, you can use the pathMatch property in your route configuration to specify the matching type. To set up aliasing you can use the redirectTo property to map one URL to another.

How do I pass data between components using Angular routing?
You can use the ActivatedRoute service to retrieve route parameters and data and use the Router service to navigate to a new route in the route's data object by passing a parameter.

What is the role of wildcards in Angular routing, and how do I use them?
Wildcards in Angular routing are used as a catch all route that is triggered when no other route matches. You can use them to display a custom 404 page or to handle any undefined routes. To use a wildcard route you can add a path with ** to your route configuration.

How do I implement authentication and authorization in Angular routing?
You can use route guards to control access to specific routes based on user roles and permissions. The CanActivate guard has the ability to allow or deny access to a route. On the other hand, the CanLoad guard can prevent lazy loaded modules from being loaded until the user is authenticated.

Can I create dynamic routes based on data fetched from an API in Angular?
Yes, you can create dynamic routes based on data fetched from an API in Angular. You can use the ActivatedRoute service to retrieve the data and use it to generate the routes in your route configuration dynamically. This can be useful for creating pages with unique content based on data from an API such as product pages or user profiles.

Tags:
BairesDev Editorial Team

By BairesDev Editorial Team

Founded in 2009, BairesDev is the leading nearshore technology solutions company, with 4,000+ professionals in more than 50 countries, representing the top 1% of tech talent. The company's goal is to create lasting value throughout the entire digital transformation journey.

Stay up to dateBusiness, technology, and innovation insights.Written by experts. Delivered weekly.

Related articles

Software Development - The Power of
Software Development

By BairesDev Editorial Team

18 min read

Contact BairesDev
By continuing to use this site, you agree to our cookie policy and privacy policy.