# Routing in Angular

In 
Published 2024-01-06

This tutorial explains routing concept in Angular.

Routing in Angular refers to the mechanism that allows you to navigate between different views or pages in a single-page application (SPA) without requiring a full-page reload. Angular provides a powerful and flexible routing system that helps you organize and manage the navigation flow of your application.

Here's a step-by-step explanation of how routing works in Angular:

# Setting Up Routes

Defining the routes in your Angular application is typically done in a dedicated routing module. A route consists of a URL path and the associated component that should be displayed when the route is activated.

Example of a routing module (app-routing.module.ts):

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';

const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'about', component: AboutComponent },
  // Additional route configurations
];

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

In this example, there are two routes: one for the home page ('') and one for the about page ('about'). The corresponding components (HomeComponent and AboutComponent) will be displayed when these routes are activated.

# Router Outlet

In the main application template (usually in app.component.html), include a <router-outlet></router-outlet> where the routed components will be displayed. The router outlet serves as a placeholder where the content of the active route will be rendered.

Example (app.component.html):

<nav>
  <a routerLink="/">Home</a>
  <a routerLink="/about">About</a>
</nav>
<router-outlet></router-outlet>

# Router Service

Use the Router service to navigate programmatically within your components or services. Inject the Router service in your component and call its navigate method with the desired route path.

Example (home.component.ts):

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

@Component({
  selector: 'app-home',
  template: `
    <h2>Home Page</h2>
    <button (click)="goToAbout()">Go to About</button>
  `
})
export class HomeComponent {
  constructor(private router: Router) {}

  goToAbout() {
    this.router.navigate(['/about']);
  }
}

In this example, clicking the "Go to About" button programmatically navigates to the 'about' route.

# Route Parameters

You can define dynamic segments in your routes to handle parameters. Parameters allow you to pass data within the URL, and you can access these parameters in the activated route.

Example (app-routing.module.ts):

const routes: Routes = [
  { path: 'user/:id', component: UserProfileComponent },
  // Additional route configurations
];

And here we can see how we can read the parameters in a ts file.

Example (user-profile.component.ts):

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-user-profile',
  template: `<p>User ID: </p>`
})
export class UserProfileComponent implements OnInit {
  userId: string;

  constructor(private route: ActivatedRoute) {}

  ngOnInit() {
    this.userId = this.route.snapshot.paramMap.get('id');
  }
}

In this example, the 'user/:id' route allows you to capture the user ID from the URL and display it in the UserProfileComponent.

# Route Guards

In Angular, route guards are used to control the navigation behavior based on certain conditions. There are different types of route guards available, and they can be applied to individual routes or to an entire module. Here are the common types of route guards and how to use them:

The CanActivate guard determines whether a route can be activated. It is commonly used to check if a user is authenticated before allowing access to a route.

Example:

// auth.guard.ts
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 {
    // Implement your authentication logic here
    const isAuthenticated = /* Check if the user is authenticated */ true;

    if (isAuthenticated) {
      return true;
    } else {
      // Navigate to the login page if not authenticated
      return this.router.createUrlTree(['/login']);
    }
  }
}

Usage in a route:

// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AuthGuard } from './auth.guard';

const routes: Routes = [
  { path: 'home', component: HomeComponent, canActivate: [AuthGuard] },
  // Other route configurations
];

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

The CanActivateChild guard is similar to CanActivate but is applied to child routes. It is used to control the activation of child routes.

Example:

// auth.guard.ts
import { Injectable } from '@angular/core';
import { CanActivateChild, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router } from '@angular/router';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class AuthGuard implements CanActivateChild {
  constructor(private router: Router) {}

  canActivateChild(
    childRoute: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    // Implement your authentication logic here
    const isAuthenticated = /* Check if the user is authenticated */ true;

    if (isAuthenticated) {
      return true;
    } else {
      // Navigate to the login page if not authenticated
      return this.router.createUrlTree(['/login']);
    }
  }
}

Usage in a route:

// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AuthGuard } from './auth.guard';

const routes: Routes = [
  {
    path: 'home',
    canActivateChild: [AuthGuard],
    children: [
      { path: 'dashboard', component: DashboardComponent },
      // Other child route configurations
    ],
  },
  // Other route configurations
];

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

The CanDeactivate guard determines whether a route can be deactivated (navigated away from). It is useful for confirming unsaved changes before leaving a page.

Example:

// unsaved-changes.guard.ts
import { Injectable } from '@angular/core';
import { CanDeactivate } from '@angular/router';
import { Observable } from 'rxjs';

export interface CanComponentDeactivate {
  canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean;
}

@Injectable({
  providedIn: 'root',
})
export class UnsavedChangesGuard implements CanDeactivate<CanComponentDeactivate> {
  canDeactivate(
    component: CanComponentDeactivate
  ): Observable<boolean> | Promise<boolean> | boolean {
    return component.canDeactivate ? component.canDeactivate() : true;
  }
}

Usage in a route:

// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { UnsavedChangesGuard } from './unsaved-changes.guard';

const routes: Routes = [
  {
    path: 'home', component: HomeComponent, canDeactivate: [UnsavedChangesGuard],
  },
  // Other route configurations
];

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