Skip to main content

Angular Router Setup

Introduction

The Angular Router is a powerful feature that enables navigation between different views in your Single Page Applications (SPAs). Rather than loading entirely new pages from the server, the router allows your application to change what the user sees by showing or hiding different components based on the URL in the browser. This creates a smoother, more app-like experience for your users.

In this tutorial, you'll learn how to set up the Angular Router in your application, define routes, navigate between components, and understand some best practices for organizing your routes.

Prerequisites

Before proceeding, you should have:

  • Basic understanding of Angular components
  • Angular CLI installed (npm install -g @angular/cli)
  • An existing Angular application or a new one created with ng new my-app

Setting Up the Router

Step 1: Installing the Router

If you created your Angular project using Angular CLI with the default settings, the router is already installed. However, if you need to add it manually to an existing project, you can install it with npm:

bash
npm install @angular/router

Step 2: Import the Router Module

To use the router in your application, you need to import the RouterModule from @angular/router in your app module:

typescript
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouterModule, Routes } from '@angular/router';

import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';
import { ContactComponent } from './contact/contact.component';

// Define your routes here
const routes: Routes = [
{ path: 'home', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: 'contact', component: ContactComponent },
{ path: '', redirectTo: '/home', pathMatch: 'full' }, // Default route
{ path: '**', component: HomeComponent } // Wildcard route for a 404 page
];

@NgModule({
declarations: [
AppComponent,
HomeComponent,
AboutComponent,
ContactComponent
],
imports: [
BrowserModule,
RouterModule.forRoot(routes) // Add RouterModule to imports array
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

Step 3: Add a Router Outlet

The router-outlet is a directive that acts as a placeholder where the router will display components when navigating between routes. Add it to your main app component template:

html
<!-- app.component.html -->
<div>
<nav>
<ul>
<li><a routerLink="/home">Home</a></li>
<li><a routerLink="/about">About</a></li>
<li><a routerLink="/contact">Contact</a></li>
</ul>
</nav>

<!-- The components matching the route will be displayed here -->
<router-outlet></router-outlet>
</div>

Understanding Routes Configuration

Let's break down the route configuration from our earlier example:

typescript
const routes: Routes = [
{ path: 'home', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: 'contact', component: ContactComponent },
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: '**', component: HomeComponent }
];

Each route is an object with properties:

  • path: The URL path segment for this route (without the leading slash)
  • component: The component to display when this route is active
  • redirectTo: (Optional) URL to redirect to when this route is matched
  • pathMatch: (Optional) Strategy for matching paths ('prefix' or 'full')
  • children: (Optional) Array of child routes

The special ** path is a wildcard that matches any URL that didn't match any of the previous routes. This is typically used for 404 error pages.

The routerLink directive is used to create navigation links in your templates:

html
<a routerLink="/about">About</a>

You can also use dynamic values with routerLink:

html
<a [routerLink]="['/user', userId]">View User Profile</a>

For the above example, if userId is 42, the resulting link would be /user/42.

Active Route Styling

To add styling to the currently active link, you can use the routerLinkActive directive:

html
<a routerLink="/home" routerLinkActive="active-link">Home</a>

With the corresponding CSS:

css
.active-link {
font-weight: bold;
color: #4285f4;
}

You can also use the [routerLinkActiveOptions] property to configure exact matching:

html
<a routerLink="/home" 
routerLinkActive="active-link"
[routerLinkActiveOptions]="{exact: true}">Home</a>

Programmatic Navigation

Sometimes you need to navigate from TypeScript code rather than through links in templates. You can use the Router service for this:

typescript
import { Router } from '@angular/router';

@Component({
selector: 'app-login',
templateUrl: './login.component.html',
})
export class LoginComponent {
constructor(private router: Router) {}

onLogin() {
// Perform login logic...

// If login is successful, navigate to dashboard
this.router.navigate(['/dashboard']);
}

onLoginWithParams() {
// Navigate with query parameters
this.router.navigate(['/dashboard'], {
queryParams: { source: 'login', returnUrl: 'settings' }
});
}
}

Route Parameters

You can define routes with parameters that capture values from the URL:

typescript
const routes: Routes = [
{ path: 'product/:id', component: ProductDetailComponent }
];

In this example, :id is a route parameter. The actual value will be provided in the URL, such as /product/123.

To access this parameter in your component:

typescript
import { ActivatedRoute } from '@angular/router';

@Component({
selector: 'app-product-detail',
templateUrl: './product-detail.component.html',
})
export class ProductDetailComponent implements OnInit {
productId: string;

constructor(private route: ActivatedRoute) {}

ngOnInit() {
// Method 1: Using snapshot (doesn't update if param changes while on same component)
this.productId = this.route.snapshot.paramMap.get('id');

// Method 2: Using observable (updates if param changes while on same component)
this.route.paramMap.subscribe(params => {
this.productId = params.get('id');
// Fetch product details with this ID
});
}
}

Organizing Routes with Feature Modules

As your application grows, you might want to split your routes into feature modules:

typescript
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { NotFoundComponent } from './not-found/not-found.component';

const routes: Routes = [
{ path: 'home', component: HomeComponent },
{ path: '', redirectTo: '/home', pathMatch: 'full' },
// Lazy loading the products module
{
path: 'products',
loadChildren: () => import('./products/products.module').then(m => m.ProductsModule)
},
{ path: '**', component: NotFoundComponent }
];

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

And in your feature module:

typescript
// products/products-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { ProductListComponent } from './product-list/product-list.component';
import { ProductDetailComponent } from './product-detail/product-detail.component';

const routes: Routes = [
{ path: '', component: ProductListComponent },
{ path: ':id', component: ProductDetailComponent }
];

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

This approach helps keep your code organized and enables lazy loading, which improves performance by loading module code only when needed.

Real-World Example: E-commerce Navigation

Let's see how you might structure routes for a simple e-commerce site:

typescript
const routes: Routes = [
{ path: 'home', component: HomeComponent },
{
path: 'products',
component: ProductsComponent,
children: [
{ path: '', component: ProductListComponent },
{ path: 'category/:categoryId', component: CategoryProductsComponent },
{ path: ':id', component: ProductDetailComponent }
]
},
{
path: 'checkout',
component: CheckoutComponent,
canActivate: [AuthGuard] // Protect this route with a guard
},
{
path: 'account',
loadChildren: () => import('./account/account.module').then(m => m.AccountModule),
canLoad: [AuthGuard] // Only load this module if user is authenticated
},
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: '**', component: PageNotFoundComponent }
];

This setup:

  • Shows a product listing at /products
  • Shows products by category at /products/category/123
  • Shows product details at /products/456
  • Protects the checkout route with an AuthGuard
  • Lazy loads the account module and only allows authenticated users to access it
  • Redirects empty routes to home
  • Shows a 404 page for undefined routes

Summary

In this tutorial, you've learned how to:

  • Set up the Angular Router in your application
  • Define routes for your components
  • Create navigation links with routerLink
  • Style active routes
  • Navigate programmatically using the Router service
  • Work with route parameters
  • Organize routes with feature modules
  • Implement real-world routing patterns

The Angular Router is a powerful tool for creating sophisticated navigation in your Single Page Applications. By mastering these fundamentals, you'll be well-equipped to build complex, user-friendly applications with smooth navigation between different views.

Additional Resources

Exercises

  1. Create a simple Angular application with at least three different routes.
  2. Implement a route with parameters and display the parameter values on the component.
  3. Add a "not found" page that displays when users navigate to non-existent routes.
  4. Create a nested route structure with parent and child routes.
  5. Implement a guard that prevents access to a route unless a condition is met (e.g., user is logged in).


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)