Categories
Angular

Routing In Angular In Depth

In this post, we will learn about routing in Angular in depth. We will start from basics and progress towards passing parameters, using child routes, protecting routes and finally routing modularization.

Angular

Introduction To Routing In Angular

Even though an Angular app is a single page appllication (SPA), the routing mechanism plays an important role to load and manage the Angular application. Routing is basically mapping of URLs to Angular components.

Angular routes are declared using Routes interface which holds an array of defined routes.

const appRoutes: Routes = [
..
]

The declared routes are then imported into Angular app from the AppModule class:

//inside AppModule
@NgModule({
  imports: [
    CommonModule,
    RouterModule.forChild(appRoutes)
  ],
...

Routing Basics

1) Use routerLink to process routes from within the Angular component.

<a routerLink="reset-password">Reset Password</a>


2) Make use of wildcard path to route paths which are not found or available.

{path: '**', component: NotFoundComponent}

3) The order of route path setup is important. If we use the wildcard at first, all paths will redirect to NotFoundComponent.

Truenary Solutions

4) Use redirectTo for redirecting any deprecated routes in the application.

{path: '', redirectTo: 'login', pathMatch:'full'},

5) Use the RouterOutlet to display the components for the given outlet.

<router-outlet></router-outlet>

Passing Route Parameters In Angular

Parameters can be passed around during routing navigation. This can be achieved in two modes:

  • Passing parameters from Angular component
  • Passing parameters programmatically

For both cases, parameters must be initially defined during route definition.

{ path: 'details/:id', component: DetailsComponent }

Similarly, multiple parameters can be setup as:

{ path: 'details/:id/:name', component: DetailsComponent }

Passing Parameters From Angular Component

To setup routerLink with parameters, use the [routerLink] array.

<a [routerLink]="['details', product.id]"> {{product.name}}</div>

Multiple parameters in a similar way:

<a [routerLink]="['details', product.id, 'seller']"> {{product.name}}</a>

Access the parameters from within the component using the ActivatedRoute class.

constructor(private routes: ActivatedRoute,) {

  }

  ngOnInit() {
    this.routes.params.subscribe(paramteres => {
      const id = paramteres['id'];      
    });

Optional parameters can be added using json objects.

<a [routerLink]="['details', product.id, 'seller', {op1: 'dog', op2: 'cat'}]"> {{product.name}}</a>

Finally, optional parameters can e accessed from component after routing in the same as before:

Passing Parameters Programatically

Use the Router module to enable passing parameters dynamically from the Angular component.

constructor(private router: Router, private productServices: ProductServices) { }

Then use the navigate method.

this.router.navigate(['details', id, 'seller']);

Similarly, we can also pass optional parameters:

this.router.navigate(['details', id, 'seller', {op1: 'dogg'}]);

Child Routes In Angular

A child route is basically a route within a route. For example, there can be multiple components within a single Login route:

  • Forgot Password component
  • Signup component
  • Login component

Setup A Child Route In Angular

We can setup child routes in the following way:

{path:'login', component: LoginComponent, children:[
    {path:'', component: LoginUserComponent},
    {path:'login', component: LoginUserComponent},
    {path:'forgot', component: ForgotPasswordComponent},
  ]},

Or if there any parameters that need to be passed onto child components:

{path:'products', component: ProductsComponent, children: [
    {path: 'details/:id', component: DetailsComponent}
  ]},

A child route can be implemented in the same way as a regular route:

<button routerLink="forgot" routerLinkActive="selected-route">Forgot Password</button>

Furthermore, a relative routing url can also be used to implement child route from parent component.

//called from ForgotPasswordComponent
<a routerLink="../login">Back To Login</a>

In order to make the child routes available, we need to use the RouterOutlet again at the parent component.

//inside the parent LoginComponent
<router-outlet></router-outlet>

Route Guards In Angular

A route guard is used to protect certain components from unauthorized users. It can tell the router whether or not it should allow navigation to a requested route.

Besides protecting a route, a route guard can also be used to prevent user’s from leaving a certain route.

How To Protect A Route In Angular

The canActivate property of Route can be used to protect a route or a child route.

It works with an array of function which resolves to a boolean value. The functions can be observables, promises or static functions.

Start by creating an injectable guard service.

ng g guard services/LoggedIn

This generates a LoggedInGuard class which implements the CanActivate interface.

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class LoggedInGuard implements CanActivate {
  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    return true;
  }
}

By default, the canActivate function resolves to true. You should change the implementation as per your application need.

Now, this service can be implemented in any needed route.

{path: 'admin', component: AdminComponent,
  canActivate: [LoggedInGuard],

Also, you need to provide the service via providers property as it is a injectable service.

providers: [LoggedInGuard],

How To Prevent Deactivating A Route

Similar to protecting route using the canActivate property, the canDeactivate property can be used to prevent from routing away from a route.

The implementation for canDeactivate is quite similar to canActivate but it does have some differences. You need to inject the component to the service for deactivating it.

Learn more about CanDeactivate

Routing Modularization Using Modules

So far we have been initializing all of routes from AppModule class itself. Although, there’s nothing wrong with this approach, however, when working on a large project, typically each child routes are defined separately by a ngModule separately for each parent route.

This pattern of separating Routing Modules for each component is called Routing Modularization in Angular.

Besides maintaining clean code, this practice also helps to improve app performance by lazy loading components.

Setup Routing Module For Components

Generate a routing module using the following command:

ng generate module my_module_name

It generates a template for Angular module:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

@NgModule({
  imports: [
    CommonModule
  ],
  declarations: []
})
export class AdminModule { }

Next, define all the routes specific to the Admin components.

const appRoutes: Routes = [
  {
    path: 'admin', component: AdminComponent,
    canActivate: [LoggedInGuard],
    children: [
      { path: '', component: UsersComponent },
      { path: 'user-list', component: UsersComponent },
      { path: 'add', component: AddUserComponent },
    ]
  }
];

You can implement the canActivate as before.

Next use the RouterModule with forChild method.

//inside AdminModule

@NgModule({
  imports: [
    CommonModule,
    RouterModule.forChild(appRoutes)
  ],
  declarations: [
    AdminComponent,
    UsersComponent,
    AddUserComponent
  ],
  providers:[LoggedInGuard]
})
export class AdminModule { }

Add any needed services as providers and finally use this module in the AppModule class.

//inside the AppModule class
imports: [
    BrowserModule,
    AdminModule,
..

Now, the app should work as expected after Routing Modularization.

Lazy Loading Of Modules

Once we have modularized routing, we can set it up to load the components only when required.

For lazy loading, we have to do three things:

  1. Remove Module import from AppModule class.
  2. Add Module as a path specifying the absolute path of the module in the AppModule routing declaration.
  3. Remove relative path from Module’s routing.

Below you can see how the module can be imported.

// step 2
//inside the AppModule's routing declaration
{path: 'admin', loadChildren: 'app/admin/admin.module#AdminModule'}
...
// step 1
//inside the AdminModule routing declaration
{ path: '', component: AdminComponent,
...

Wrapping Up Routing In Angular

Ok, now we have covered everything there is to know about Routing in Angular app. To summarize we learnt about:

  • Basics Of Routing In Angular
  • Passing Parameters
  • Routing From Component And Class
  • Creating Child Routes
  • Protecting Routes
  • Routing Modularization

I hope this was a good guide to learn about Routing in Angular. Stay tuned for more content on Angular.

Learn Mobile App Development With Flutter

Leave a Reply

Your email address will not be published. Required fields are marked *