Angular Routing and Navigation: Creating Single-Page Applications
Published: 2023-07-24 12:25:25

In today's realm of modern web development, single-page applications (SPAs) have garnered immense popularity owing to their superior user experience and optimized performance. Among the myriad of front-end frameworks available, Angular stands out as a potent choice, offering extensive features to construct SPAs, particularly with its robust routing and navigation capabilities. 

In this technical blog, we embark on an exploration of the fundamental concepts behind Angular routing and navigation, delving into the process of crafting dynamic and responsive SPAs.


## Introduction to Angular Routing:

Routing is the process of determining the component that should be displayed for a given URL. In traditional multi-page applications, each page is served by a separate server request. However, in SPAs, only the initial request loads the entire application, and subsequent requests are handled by the client-side router, without requiring a full page reload.

Angular's built-in router allows developers to define navigation paths and associate them with specific components, enabling seamless navigation between different views without causing a complete page refresh. This not only enhances the user experience but also improves the performance of the application.


## Setting Up an Angular Project:

Before diving into Angular routing, let's set up an Angular project. Ensure that you have Node.js and the Angular CLI installed on your system. Open a terminal and use the following commands:

# Install Angular CLI globally
npm install -g @angular/cli

# Create a new Angular project
ng new my-spa-app
cd my-spa-app


## Defining Routes:

In Angular, routes are defined in the app-routing.module.ts file. This module is automatically generated when you create a new Angular project. The RouterModule is imported from @angular/router, and routes are defined using the Routes interface.

Let's define some basic routes for our SPA:

// 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';
import { ContactComponent } from './contact/contact.component';

const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'about', component: AboutComponent },
  { path: 'contact', component: ContactComponent },
];

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



In the code above, we've defined three routes: the empty path corresponds to the HomeComponent, while /about and /contact paths correspond to the AboutComponent and ContactComponent, respectively.


## Creating Components for Routes:

Now that we have defined our routes, let's create the components for each route. Angular CLI makes it easy to generate components:

# Generate components
ng generate component home
ng generate component about
ng generate component contact


These commands will create three folders inside the src/app directory, each containing the necessary files for the corresponding components.


## Displaying the Components:

Next, let's display the components in our app. In the app.component.html, replace the default content with the <router-outlet> tag:

<!-- app.component.html -->
<router-outlet></router-outlet>


## Navigating Between Routes:

With our components and routes set up, we can now navigate between them. Angular provides the routerLink directive to navigate between routes. Update the app.component.html to include navigation links:

<!-- app.component.html -->
<nav>
  <a routerLink="/">Home</a>
  <a routerLink="/about">About</a>
  <a routerLink="/contact">Contact</a>
</nav>
<router-outlet></router-outlet>


The routerLink directive provides a convenient way to navigate to different routes within our SPA.

Configuring Navigation with Parameters:

Often, we need to pass parameters to a route. For example, in a blog application, we might want to display a specific blog post based on its ID. Angular's routing system allows us to handle such scenarios effortlessly.

Let's create a new component for displaying blog posts:

ng generate component blog-post

In our app-routing.module.ts, we'll modify the route for the BlogPostComponent to accept a parameter:

// 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';
import { ContactComponent } from './contact/contact.component';
import { BlogPostComponent } from './blog-post/blog-post.component';

const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'about', component: AboutComponent },
  { path: 'contact', component: ContactComponent },
  { path: 'blog/:id', component: BlogPostComponent },
];

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


The :id part of the route is a parameter placeholder. When the route is navigated with a specific blog ID, it will be passed as a parameter to the BlogPostComponent.

Now, in the BlogPostComponent, we can access the parameter using Angular's ActivatedRoute:


// blog-post.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-blog-post',
  templateUrl: './blog-post.component.html',
  styleUrls: ['./blog-post.component.css']
})
export class BlogPostComponent implements OnInit {
  postId: string;

  constructor(private route: ActivatedRoute) { }

  ngOnInit(): void {
    this.route.paramMap.subscribe(params => {
      this.postId = params.get('id');
      // Fetch blog post details using the post ID
    });
  }
}


Now, when navigating to a URL like /blog/123, the BlogPostComponent will extract the value 123 as the postId parameter and fetch the corresponding blog post details.


## Handling Redirects and 404 Errors:

In some cases, we might want to redirect users from one route to another. Angular provides the redirectTo property to achieve this:

// app-routing.module.ts
const routes: Routes = [
  // ...
  { path: 'old-route', redirectTo: '/new-route' },
  // ...
];

The above route configuration will redirect any request to /old-route to /new-route.

Additionally, we can handle 404 errors for routes that do not exist. To do this, add a wildcard route at the end of the route configuration:

// app-routing.module.ts
const routes: Routes = [
  // ...
  { path: 'not-found', component: NotFoundComponent },
  { path: '**', redirectTo: '/not-found' },
];


Any URL that does not match any defined route will be redirected to the NotFoundComponent.


## Guarding Routes:

Angular also allows us to guard routes to control access based on user authentication or other conditions. There are three types of guards: CanActivate, CanActivateChild, and CanDeactivate.

For example, let's implement a simple authentication guard to restrict access to a route:

// 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 {
      
    // Check if the user is authenticated
    const isAuthenticated = ...; // Replace with your authentication logic

    if (isAuthenticated) {
      return true;
    } else {
      // Redirect to the login page if not authenticated
      return this.router.parseUrl('/login');
    }
  }
}

To use the AuthGuard, add it to the route configuration for the routes that need protection:

// app-routing.module.ts
const routes: Routes = [
  // ...
  { path: 'protected-route', component: ProtectedComponent, canActivate: [AuthGuard] },
  // ...
];


Now, the ProtectedComponent will only be accessible if the AuthGuard returns true, meaning the user is authenticated.


## Conclusion: 

Leveraging Angular's powerful routing and navigation capabilities, developers can create impressive single-page applications (SPAs) that enhance user experience and improve overall performance. Angular's built-in router allows for the definition of navigation paths and component associations, enabling seamless transitions between different views without page reloads.

For businesses seeking to harness the full potential of Angular development and build cutting-edge SPAs, partnering with an experienced [Angular development company](https://www.zealousys.com/technology/angular-development/) is a strategic move. These specialized companies possess the expertise and proficiency needed to develop robust, scalable, and feature-rich SPAs that cater to specific business requirements.