Routing is one of the most essential features of modern web applications. It allows users to navigate between different views or components based on the URL in the browser. In Angular, routing is managed using the Angular Router, which provides a powerful way to map URLs to specific components.
What is Routing?
Routing refers to the mechanism of navigating between different parts of an application. In Angular, routes are defined in a central configuration and then used to determine which component should be displayed when a user navigates to a specific path.
Setting Up Angular Router
Before we can define routes, we need to set up Angular Router in our application. Typically, this is done when creating a new Angular project using the Angular CLI with the routing flag:
ng new my-app --routing
This command automatically generates a app-routing.module.ts
file where we can define our routes.
If routing was not set up initially, we can manually add it:
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
@NgModule({
imports: [RouterModule.forRoot([])],
exports: [RouterModule]
})
export class AppRoutingModule { }
Defining Basic Routes
Routes in Angular are defined as an array of objects, each describing a path and the component to be rendered for that path. Here is a basic example:
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 }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Explanation of the Code
- Importing RouterModule and Routes:
These imports are essential for defining the routing configuration.Routes
is a type representing an array of route objects. - Creating Components:
HomeComponent
andAboutComponent
are Angular components linked to specific paths. - Defining the Route Array:
Each object in the array represents a route. Thepath
is the URL segment, andcomponent
is the component displayed when the path is matched. - Empty Path
''
:
An empty path typically represents the root URL (http://localhost:4200/
) and usually loads the main or home component. - RouterModule.forRoot(routes):
This method registers the routes with Angular.forRoot
is used once in the application for the main routing configuration.
Using RouterOutlet
To display the routed components, Angular uses the <router-outlet>
directive. It acts as a placeholder in the template for the routed components:
<app-header></app-header>
<router-outlet></router-outlet>
<app-footer></app-footer>
How RouterOutlet Works
- When the URL matches a defined route, the corresponding component is dynamically inserted into the
<router-outlet>
. - This allows multiple views to share a common layout, such as a header and footer.
Adding Navigation
To navigate between routes, Angular provides the routerLink
directive:
<nav>
<a routerLink="">Home</a>
<a routerLink="about">About</a>
</nav>
Programmatic Navigation
Sometimes, you might want to navigate using code rather than links. Angular provides the Router
service for this:
import { Component } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'app-navigation',
template: <button (click)="goToAbout()">Go to About</button>
})
export class NavigationComponent {
constructor(private router: Router) { }
goToAbout() {
this.router.navigate(['/about']);
}
}
Route Parameters
Angular routes can accept parameters to pass dynamic data. For example, if we want to display a user profile based on an ID:
const routes: Routes = [
{ path: 'user/:id', component: UserComponent }
];
In the component, we can access the parameter:
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-user',
template: <p>User ID: {{ userId }}</p>
})
export class UserComponent implements OnInit {
userId!: string;
constructor(private route: ActivatedRoute) { }
ngOnInit() {
this.userId = this.route.snapshot.paramMap.get('id')!;
}
}
Nested Routes (Child Routes)
Angular supports nested routes to create hierarchies of views. For example, if we have a DashboardComponent
with child views:
const routes: Routes = [
{ path: 'dashboard', component: DashboardComponent, children: [
{ path: 'stats', component: StatsComponent },
{ path: 'reports', component: ReportsComponent }
]}
];
In the DashboardComponent
template:
<h2>Dashboard</h2>
<router-outlet></router-outlet>
The child components StatsComponent
and ReportsComponent
will render inside the dashboard’s <router-outlet>
.
Redirecting Routes
Angular allows redirecting one route to another using the redirectTo
property:
const routes: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
{ path: 'about', component: AboutComponent }
];
Explanation
redirectTo
: Specifies the target path to redirect to.pathMatch: 'full'
: Ensures the full URL is matched before redirecting. Without this, Angular may partially match and redirect incorrectly.
Wildcard Routes
Wildcard routes handle unknown paths, typically for 404 pages:
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: '**', component: PageNotFoundComponent }
];
**
matches any route that does not exist in the defined route array.- Always place wildcard routes at the end, otherwise they will override all other routes.
Lazy Loading Modules
For large applications, Angular supports lazy loading, which loads feature modules only when the route is accessed. Example:
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'about', loadChildren: () => import('./about/about.module').then(m => m.AboutModule) }
];
This improves performance by reducing the initial bundle size.
Route Guards
Route guards control access to routes based on conditions, like authentication:
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
constructor(private router: Router) { }
canActivate(): boolean {
const loggedIn = false; // Replace with actual authentication check
if (!loggedIn) {
this.router.navigate(['/']);
return false;
}
return true;
}
}
Usage in routes:
const routes: Routes = [
{ path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] }
];
Route Resolvers
Resolvers fetch data before a route is activated:
@Injectable({ providedIn: 'root' })
export class UserResolver implements Resolve<User> {
constructor(private userService: UserService) { }
resolve(route: ActivatedRouteSnapshot): Observable<User> {
return this.userService.getUser(route.paramMap.get('id')!);
}
}
Usage in routes:
const routes: Routes = [
{ path: 'user/:id', component: UserComponent, resolve: { user: UserResolver } }
];
In the component:
ngOnInit() {
this.route.data.subscribe(data => {
this.user = data['user'];
});
}
Leave a Reply