Angular Routing & Navigation


What is Routing and Navigation in Angular 2?

• Routing is the process of driving the UI of an application using URLs.
• It is a powerful JavaScript router built and maintained by the Angular core team.
• It is a core part of the Angular platform and enables developers to build SPA (Single Page Application) with multiple views and allow navigation between these views.
• It can be installed from the @angular/router package, and provides a complete routing library which have multiple router outlets, different path matching, easy access to route parameters and route guards to protect components from unauthorized access.
• It allows client side navigation and routing between the various components.
• Routing in Angular is also referred as component routing because the Router maps a single or a hierarchy of components to a specific URL.
 Single Page Application-
A single-page application (SPA) is a web application or web site that interacts with the user by dynamically rewriting the current page rather than loading entire new pages from a server.
In this only one page is requested from the server. The multiple views that we can transition to are not fetched as new pages from the server rather it is rendered dynamically by the browser.
 Different types of Routing-
1) Client Side Routing: In this the browser has already retrieved all the application in the first place and the logic to show the requested view will be done in the browser with JavaScript. It dynamically displays different content depending on the current URL. It includes the Angular Router, React Router and Vue Router.
2) Server Side Routing: In server side routing, when the user navigates to a specific page, the browser sends a request to get the page from the server and display it.
 Features of Angular Router-
 The support for multiple Router outlets which easily add complex routing scenario like nested routing.
 It activates all required Angular components to compose a page when a user navigates to a certain URL
 It lets users navigate from one page to another without page reload.
 It updates the browser’s history so the user can use the back and forward buttons when navigating back and forth between pages.
 redirect a URL to another URL.
 resolve data before a page is displayed.
 run scripts when a page is activated or deactivated.
 How Angular Router works-
When a user navigates to a page, Angular Router performs the following steps-
• Reads the browser URL the user wants to navigate to.
• Applies a URL redirect (if one is defined).
• Figures out which router state corresponds to the URL.
• Runs the guards that are defined in the router state.
• Resolves the required data for the router state.
• Activates the Angular components to display the page.
• Manages navigation and repeats the steps above when a new page is requested.
 Angular Router introduces the following terms -
 router service: Global Angular Router service in our application.
 router configuration: Definition of all possible router states our application.
 router state: State of the router at some point of time, expressed as a tree of activated route snapshots.
 activated route snapshot: Provides access to the URL, parameters, and data for a router state node.
 guard: Script that runs when a route is loaded, activated or deactivated.
 resolver: Script that fetches data before the requested page is activated.
 router outlet: Location in the DOM where Angular Router can place activated components.
 Enabling Routing
To enable routing in our Angular application we need to do three things-
• Create a routing configuration that defines the possible states for our application.
• Import the routing configuration into our application.
• Add a router outlet to tell Angular Router where to place the activated components in the DOM.
 Two ways to create a routing module
1) RouterModule.forRoot(routes): creates a routing module that includes the router directives, the route configuration and the router service. It can be used only once routing module.
2) RouterModule.forChild(routes): creates a routing module that includes the router directives, the route configuration but not the router service. The RouterModule.forChild() method is needed when your application has multiple routing modules. It can be used multiple times for additional routing modules.
Note: Router service takes care of synchronization between our application state and the browser URL. Instantiating multiple router services that interact with the same browser URL would lead to issues, so it is essential that there’s only one instance of the router service in our application, no matter how many routing modules we import in our application.
 Different parameters in Angular Router-
a) The Components, routes and paths
b) The Router-Outlet
c) The route matching strategies
d) Route parameters
e) Query parameters
f) Route guards
g) Route resolvers
h) The routerLink directive (replaces the href attribute)
i) Auxiliary routes
 The Component, Routes and Paths
• In Angular, a route is an object that provides information about which component maps to a specific path.
• A path is the fragment of a URL that determines where exactly the resource (or page) is located which we want to access. We can get the path by taking off the domain name from the URL.
• In Angular we can define a route using route configurations or instances of the Route interface.
• Each Route maps a URL path to a component.
• The path can be empty which denotes the default path of an application and it’s usually the start of the application.
• The path can take a wildcard string (**). The router will select this route if the requested URL doesn’t match any paths for the defined routes. This can be used for displaying a “Not Found” view or redirecting to a specific view if no match is found.
• Each route can have the following properties-
i. path is a string that specifies the path of the route.
ii. pathMatch is a string that specifies the matching strategy. It can take prefix (default) or full.
iii. component is a component type that specifies the component that should be mapped to the route.
iv. redirectTo is the URL which we will be redirected to if a route is matched.
Example of a route:
{ path: 'contacts', component: EmployeeListComponent}
Explanation- If this route definition is provided to the Router configuration, the router will render EmployeeListComponent when the browser URL for the web application becomes /employeeList.
 The Router-Outlet
The Router-Outlet is a directive available from the router library where the Router inserts the component that gets matched based on the current browser’s URL. We can add multiple outlets in our Angular application which enables us to implement advanced routing scenarios.
Syntax-
Note:- Any component that gets matched by the Router will render it as a sibling of the Router outlet.
 The route matching strategies
It provides different route matching strategies. There are two route matching strategies-
i. built-in matching strategies
ii. custom matching strategies
built-in matching strategies-
• The built-in matching strategies are prefix (the default) and full.
• The default strategy is simply checking if the current browser’s URL is prefixed with the path.
For Example-
{ path: 'contacts', component: EmployeeListComponent}
Can also be written as-
{ path: 'contacts',pathMatch: 'prefix', component: EmployeeListComponent }
Note: The pathMatch attribute specifies the matching strategy. In this case, it’s prefix which is the default.
custom matching strategies-
We can use custom matcher if the combination of the path property and matching strategy doesn’t help us to match our component to a specific URL. We can provide a custom matcher using the matcher property of a route definition. When it’s specified for a route, the router will check if the path is exactly equal to the path of the current browser’s URL: For an example-
{ path: 'contacts',pathMatch: 'full', component: EmployeeListComponent }
 Route parameters
Dynamic routes are used in web applications to pass data (parameters) to the application or between various components and pages. The Angular router support dynamic paths and provides an easy way to use API to access route parameters. We create a route parameter using the colon syntax. Example of route with an id parameter:
{ path: 'contacts/:id', component: StudentDetailComponent}
Angular Router allows us to access parameters in different ways:
i. Using the ActivatedRoute service
ii. Using the ParamMap observable
Activated Route –
ActivatedRoute is an interface and contains the information about a route associated with a component loaded into an outlet and it can also be used to traverse the router state tree.
interface ActivatedRoute { snapshot: ActivatedRouteSnapshot url: Observable params: Observable queryParams: Observable fragment: Observable data: Observable outlet: string component: Type | string | null routeConfig: Route | null root: ActivatedRoute parent: ActivatedRoute | null firstChild: ActivatedRoute | null children: ActivatedRoute[] pathFromRoot: ActivatedRoute[] paramMap: Observable queryParamMap: Observable toString(): string }
Description
@Component({...}) class MyComponent { constructor(route: ActivatedRoute) { const id: Observable = route.params.map(p => p.id); const url: Observable = route.url.map(segments => segments.join('')); // route.data includes both `data` and `resolve` const user = route.data.map(d => d.user); } }
Properties-
Properties Description snapshot: ActivatedRouteSnapshot The current snapshot of this route. url: Observable An observable of the URL segments matched by this route. params: Observable An observable of the matrix parameters scoped to this route. queryParams: Observable An observable of the query parameters shared by all the routes. fragment: Observable An observable of the URL fragment shared by all the routes. data: Observable An observable of the static and resolved data of this route. outlet: string The outlet name of the route. It's a constant. component: Type | string | null The component of the route. It's a constant. routeConfig: Route | null The configuration used to match this route (Read-only). root: ActivatedRoute The root of the router state (Read-only). parent: ActivatedRoute | null The parent of this route in the router state tree (Read-only). firstChild: ActivatedRoute | null The first child of this route in the router state tree (Read-only). children: ActivatedRoute[] The children of this route in the router state tree (Read-only). pathFromRoot: ActivatedRoute[] The path from the root of the router state tree to this route (Read-only). paramMap: Observable Read-only. queryParamMap: Observable Read-only. Methods- toString() : toString(): string | Parameters: No parameters | Returns: string ParamMap- An Observable that contains a map of the required and optional parameters specific to the route. The map supports retrieving single and multiple values from the same parameter. ParamMap for routes like- Syntax- user/:id. Explanation- Id param belongs only this route. interface ParamMap { keys: string[] has(name: string): boolean get(name: string): string | null getAll(name: string): string[] } Properties- keys: string[] - Name of the parameters (Read-only) . Methods- has() - has(name: string): boolean Parameters- name string Returns- boolean get() - get(name: string): string | null Return a single value for given parameter name • the value when the parameter has a single value. • the first value if the parameter has multiple values. • null when there is no such parameter. Parameters- name string Returns- string | null getAll() - getAll(name: string): string[] Return an array of values for given parameter name Parameters - name string Returns - string[] Note: If there is no such parameter, an empty array is returned.
 Query parameters
An Observable that contains a map of the query parameters available to all routes. The map supports retrieving single and multiple values from the query parameter.
QueryParamMap is for e.g. user/:id?tab=edit
Tab is a global query param, it can be read from the ActivatedRoute in the user route's component as well as any of its ancestors.
 Route guards
A route guard one of the feature of the Angular Router that allow developers to run some logic when a route is requested, and based on that logic, it allows or denies the user access to the route. It’s commonly used to check if a user is logged in and has the authorization before he can access a page.
We can add a route guard by implementing the CanActivate interface available from the @angular/router package and extends the canActivate() method which holds the logic to allow or deny access to the route. For example, the following guard will always allow access to a route:
class MyGuard implements CanActivate { canActivate() { return true; } }
You can protect a route with the guard using the canActivate attribute-
{ path: 'contacts/:id, canActivate:[MyGuard], component: EmployeeDetailComponent }
 Route resolvers
Router provides a resolve property that takes a route resolver and allows our application to fetch the data before navigating to the route (i.e. resolving route data). We can create a route resolver by implementing the Resolve interface. For example,
import { Injectable } from '@angular/core'; import { APIService } from './api.service'; import { Resolve } from '@angular/router'; @Injectable() export class APIResolver implements Resolve { constructor(private apiService: APIService) {} resolve() { return this.apiService.getItem(); } }
Explanation: In the example, we assume we have already created an APIService which has a getItem() method that fetches data from a remote API endpoint.
• We import the Resolve interface from the @angular/router package.
• We then create an APIResolver class that implements the Resolve
interface.
• In the constructor of the resolver we inject our APIService as apiService and we call the getItems() method of the service in the resolve() method that should be defined in any resolver.
• When resolving route data, we want to get access to the parameters of the route in the resolver and we can do that using the ActivatedRouteSnapshot class.
• For example, let's suppose our route has a date parameter that needs to be passed to the getItem(date) method-
import { Injectable } from '@angular/core'; import { APIService } from './api.service'; import { Resolve } from '@angular/router'; import { ActivatedRouteSnapshot } from '@angular/router'; @Injectable() export class APIResolver implements Resolve { constructor(private apiService: APIService) {} resolve(route: ActivatedRouteSnapshot) { return this.apiService.getItems(route.params.date); } }
We import the ActivatedRouteSnapshot class from the @angular/router package
We provide a parameter route of type ActivatedRouteSnapshot to the resolve() method.
Finally we use route.params.date to get the value of the date parameter.
Now pass the resolver we created to resolve property of the corresponding route in the Routes array of our Angular routing module:
{ path: 'items/:date', component: ItemComponent, resolve: { items: APIResolver } }
 The routerLink directive (replaces the href attribute)

The Angular Router provides the routerLink directive to create navigation links. This directive takes the path associated with the component to navigate to. For example:  Auxiliary routes
Angular Router supports multiple outlets in the same application. It enables developers to navigate multiple routes at the same time. A component has one associated primary route and can have auxiliary routes.
To create an auxiliary route, we need a named router outlet where the component associated with the auxiliary route will be displayed.
- Primary Router Outlet - Secondary Router Outlet
Primary router outlets : The outlet with no name is the primary outlet.
Secondary router outlets : All outlets should have a name except for the primary outlet. We can specify the outlet where we want to render our component using the outlet attribute-
{ path: "contacts", component: ContactListComponent, outlet: "outlet1" }
 The Lifecycle of a Router
1) NavigationStart: Represents the start of a navigation cycle.
2) NavigationCancel: For an instance, a guard refuses to navigate to a route.
3) RoutesRecognized: When a URL has been matched to a route.
4) NavigationEnd: Triggered when navigation ends successfully.
 Steps to implement Routing in an Angular 2 application with example-
Step 1 − Add the base reference tag in the index.html file.
Angular QuickStart
Step 2 − Create two routes for the application. For this, create 2 files called Inventory.component.ts and product.component.ts
Step 3 − Place the following code in the product.component.ts file.
import { Component } from '@angular/core'; @Component ({ selector: 'my-app', template: 'Products', }) export class Appproduct { }
Step 4 − Place the following code in the Inventory.component.ts file.
import { Component } from '@angular/core'; @Component ({ selector: 'my-app', template: 'Inventory', }) export class AppInventory { }
Both components render the keywords based on the component. So for the Inventory component, it will display the Inventory keyword to the user. And for the products component, it will display the product keyword to the user. Step 5 − In the app.module.ts file, add the following code –
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; import { Appproduct } from './product.component'; import { AppInventory } from './Inventory.component'; import { RouterModule, Routes } from '@angular/router'; const appRoutes: Routes = [ { path: 'Product', component: Appproduct }, { path: 'Inventory', component: AppInventory }, ]; @NgModule ({ imports: [ BrowserModule, RouterModule.forRoot(appRoutes)], declarations: [ AppComponent,Appproduct,AppInventory], bootstrap: [ AppComponent ] }) export class AppModule { }

Note: The appRoutes contain 2 routes, one is the Appproduct component and the other is the AppInventory component. Ensure to declare both the components. RouterModule.forRoot add the routes to the application. Step 6 − In the app.component.ts file, add the following code.
import { Component } from '@angular/core'; @Component ({ selector: 'my-app', template: ` ` }) export class AppComponent { }
Note: is the placeholder to render the component based on which option the user chooses.
Step 7 - Now, save all the code and run the application using npm. Go to the browser, we will see the following output.
Now if we click the Inventory link, you will get the following output.
 Adding an Error Route or a wildcard route
In Routing, we can also add an error route. It happens if the user goes to a page which does not exist. To handle unmatched URLs we need to do two things-
a. Create PageNotFoundComponent to display a message that the requested page could not be found
b. Tell Angular Router to show the PageNotFoundComponent when no route matches the requested URL.
Step 1 − Add a PageNotFound component as NotFound.component.ts .
Step 2 − Add the following code to the NotFound.component.ts file.
import { Component } from '@angular/core'; @Component ({ selector: 'my-app', template: 'Not Found', }) export class PageNotFoundComponent { }
Step 3 − Add the following code to the app.module.ts file.
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; import { Appproduct } from './product.component' import { AppInventory } from './Inventory.component' import { PageNotFoundComponent } from './NotFound.component' import { RouterModule, Routes } from '@angular/router'; const appRoutes: Routes = [ { path: 'Product', component: Appproduct }, { path: 'Inventory', component: AppInventory }, { path: '**', component: PageNotFoundComponent } ]; @NgModule ({ imports: [ BrowserModule, RouterModule.forRoot(appRoutes)], declarations: [ AppComponent, Appproduct, AppInventory, PageNotFoundComponent], bootstrap: [ AppComponent ] }) export class AppModule { }
Note: Now we have an extra route called path: '**', component: PageNotFoundComponent. Hence, ** is for any route which does not fit the default route. They will be directed to the PageNotFoundComponent component. Now, save all the code and run the application using npm. Go to your browser, and we will see the following output. Now, when we go to any wrong link we will get the following output-
 Steps to implement Navigation or Adding a wildcard route in Angular 2 with an example-
Step 1 − Add the following code to the Inventory.component.ts file.
import { Component } from '@angular/core'; import { Router } from '@angular/router'; @Component ({ selector: 'my-app', template: 'Inventory Back to Products' }) export class AppInventory { constructor(private _router: Router){} onBack(): void { this._router.navigate(['/Product']); } }
Note: Declare an html tag which has an onBack function tagged to the click event. Thus, when a user clicks this, they will be directed back to the Products page. In the onBack function, use the router.navigate to navigate to the required page.
Step 2 − Now save all the code and run the application using npm. Go to the browser, you will see the following output.
Step 3 − Click the Inventory link.
Step 4 − Click the ‘Back to products’ link, you will get the following output which takes you back to the Products page.
 Lazy Loading in Angular 2-
• Lazy loading module helps us decrease the startup time.
• It is a technique in Angular that allows us to load JavaScript components asynchronously when a specific route is activated.
• With this our application does not need to load everything at once and allows you to load the pieces of code on demand.
• Modules that are lazily loaded will only be loaded when the user navigates to their routes.
 The benefits of Lazy Loading in Angular 2 are -
• Keep the initial payload small.
• Smaller payloads lead to faster download speeds.
• Lower resource costs especially on mobile networks.
• If a user doesn't visit a section of our app, they won't ever download those resources.
 Rules for lazy loading -
• Move components and assets into their own module.
• DO NOT load the module in the main AppModule.
• Lazy loading will be setup in the main routing file.
 Implementation of lazy loading –
We can do it in 4 steps:
Final Folder Structure :-
app - electronic
- electronic.department.component.ts
- electronic.department.module.ts
- electronic.department.routing.ts
- clothing
- clothing.department.component.ts
- clothing.department.module.ts
- clothing.department.routing.ts
- home.component.ts
- home.routing.ts
- home.module.ts
Step 1: Update your route file- app/home.routing.ts
import { homeComponent } from './home.component’; import { electronicDepartmentComponent } from './electronic/electronic.department.component'; import { clothingDepartmentComponent } from './clothing/clothing.department.component'; const homeRoutes: Routes = [ { path: '', redirectTo: 'home', pathMatch: 'full' }, { path: 'home', component: ‘homeComponent’ }, { path: 'electronicDepartment', component: 'electronicDepartmentComponent' }, { path: 'clothingDepartment', component: 'clothingDepartmentComponent' } ]; export const HomeRoutes = RouterModule.forRoot( homeRoutes); We remove the component property and all its imports. Then add ‘loadChildren’ property instead of ‘component’ property. We mention the path of the module and module class name to ‘loadChildren’. import { homeComponent } from './home.component'; // electronicDepartmentComponent and clothingDepartmentComponent are // removed from the imports const homeRoutes: Routes = [ { path: '',redirectTo: 'home', pathMatch: 'full'}, { path: 'home', component: ‘homeComponent’ }, { path: 'electonicDepartment', loadChildren: './electronic/electronic.department.module#electronicDepartmentModule' }, { path: 'clothingDepartment', loadChildren: './clothing/clothing.department.module#clothingDepartmentModule' } ]; export const HomeRoutes = RouterModule.forRoot( homeRoutes);
Here #electronicDepartmentModule and #clothingDepartmentModule are the exported class names of electronic.department.module.ts and clothing.department.module.ts respectively.
Step 2- We have pass the string path to ‘loadChildren’ but our configuration don’t know how to load this string path. We need ‘angular-router-loader’.
npm install angular-router-loader then add the loader to your webpack config file.
config.module = { rules: [ // Support for .ts files. { test: /\.ts$/, loaders: ['angular2-template-loader', 'angular-router-loader' ], },
Step 3- Define the lazy routes.
Add the routes for electronicDepartment and clothingDetpartment.
Note: We define lazy loading routes in their own module. Home component should not know about it. Therefore remove electronicDepartmentModule and clothingDepartmentModule from home.component.module as well. app/electronic/electronic.department.routing.ts
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { electronicDepartmentComponent } from './electronic.department.component'; const electronicDepartmentRoutes: Routes = [ { path : '', component : electronicDepartmentComponent } ]; @NgModule ( { imports : [ RouterModule.forChild ( electronicDepartmentRoutes) ], exports : [ RouterModule ], } ) export class electronicDepartmentRoutingModule { } app/clothing/clothing.department.routing.ts import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { clothingDepartmentComponent } from './clothing.department.component'; const clothingDepartmentRoutes: Routes = [ { path : '', component : clothingDepartmentComponent } ]; @NgModule ( { imports : [ RouterModule.forChild ( clothingDepartmentRoutes) ], exports : [ RouterModule ], } ) export class clothingDepartmentRoutingModule { }
Note: we are using RouterModule.forChild instead of RouterModule.forRoot to create routing object.
Step 4 - Import the routes to module.
Import electronicDepartmentRoutingModule and clothingDepartmentRoutingModule to electronicDepartmentModule and clothingDepartmentModule respectively. app/electronic/electronic.department.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ElectronicDepartmentComponent} from './electronic.department.component'; import { ElectronicDepartmentRoutingModule} from './electronic.department.routing'; @NgModule({ imports: [ CommonModule, ElectronicDepartmentRoutingModule ], declarations: [ ElectronicDepartmentComponent ], exports: [ ElectronicDepartmentComponent ], providers: [ ] }) export class ElectronicDepartmentModule{ } app/clothing/clothing.department.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ClothingDepartmentComponent} from './clothing.department.component'; import { ClothingDepartmentRoutingModule} from './clothing.department.routing'; @NgModule({ imports: [ CommonModule, ClothingDepartmentRoutingModule ], declarations: [ ClothingDepartmentComponent ], exports: [ ClothingDepartmentComponent ], providers: [ ] }) export class ClothingDepartmentModule{ }
Explanation- When user visits the application, at first, only home component will get loaded. When user clicks on electronic department or clothing department then respective module will get loaded as per the user’s selection. This decreases initial load time, application feels snappy and it improves user experience of the application.
Example-
app.component.ts import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { RouterModule, Routes } from '@angular/router' const routes: Routes = [ { path: 'admin', loadChildren: './admin/admin.module#AdminModule' }, { path: 'dashboard', loadChildren: './dashboard/dashboard.module#DashboardModule' } ] @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, RouterModule.forRoot(routes), ], providers: [], bootstrap: [AppComponent] }) export class AppModule { } app.component.html Admin Dashboard