Overview Of Routing In Angular 2

This article is in continuation of our Angular 2 series. If you haven’t had a look at the previous articles, then check-out this link. This will be the last part of theAngular 2 series where we’ll talk about Routing. I’ll split this article into 2 parts since routing is such a  broad topic. Every application consists of sets of pages which can be accessed through links, menu-items etc. In Angular 2, routing enables navigation between these discrete application views. For implementing routing in our application, we need to import “RouterModule” of Angular 2 like how we imported “HttpModule” for making server calls. As I have already mentioned, Angular 2 is fully modularized, every feature has its own module. Here is the import statement that I’ve added in our application's root module i.e. app.module.ts file.

  1. import { RouterModule, Routes } from '@angular/router';   

To set up with Angular 2 routing, we need to specify the application base path which is an HTML element needed to be placed beneath <head> element. By default, Angular 2 router follows HTML5 pushState style URLs. So, inside our index.html file, I’ve added the below line under the head element to tell Angular router how to compose navigation URLs.

  1. <base href="/"/>  

The next step is to set up the router-outlet, where navigated View contents should be displayed. Router-Outlet is a built  in Angular directive defined in RouterModule. It acts as a placeholder for rendering navigated View contents. I’m placing this outlet inside my app.component.ts file which is our root component for our application. Here is the updated app.component.ts file, 

  1. import { Component } from '@angular/core';  
  2.   
  3. @Component({  
  4.   selector: 'my-app',  
  5.   template: <nav class="navbar navbar-inverse">                <div class='container-fluid'>  
  6.                     <a class='navbar-brand'>{{orgName}}</a>  
  7.                     <ul class='nav navbar-nav'>  
  8.                         <li><a>Home</a></li>  
  9.                     </ul>  
  10.                 </div>  
  11.                 </nav>    
  12.                 <div class='container'>  
  13.                     <router-outlet></router-outlet>  
  14.                 </div>        
  15.          </div>`  
  16. })  
  17. export class AppComponent {  
  18.   orgName: string = "Angular2 Series";  
  19. }   

Our navigation bar has just one menu with name “HOME”.  The last part is configuring our route for the application. A routed Angular application has one singleton instance of the Router service. When browser’s URL changes, the router looks for the corresponding route & loads the respective component to display. By default, a RouterModule has no route until you configure it. For configuring route, I’m adding a new file at root level with name “app.route-config.ts”. Below is the code snippet for the same.

  1. import {Routes } from '@angular/router';  
  2. import{WelcomeComponent}  from './welcome/welcome.component';  
  3.   
  4. export const routeConfig: Routes = [  
  5.     {  
  6.         path: 'welcome',  
  7.         component: WelcomeComponent  
  8.     }  
  9. ]   

NOTE

Welcome component is an empty class with template displaying the message “This is our welcome page”.

Now that we’ve configured our route for the application, we are just left with set up of Routing in our application and to do that, we need to simply pass this routeConfig collection to RouterModule.forRoot() function. Here is the updated code snippet for app.module.ts file. 

  1. /** Importing the angular modules from namespace */  
  2. import { NgModule } from '@angular/core';  
  3. import { FormsModule } from '@angular/forms';  
  4. import { BrowserModule } from '@angular/platform-browser';  
  5. import { HttpModule } from '@angular/http';  
  6. import { RouterModule, Routes } from '@angular/router';  
  7. /** Importing the AppComponent from the application's app folder */  
  8. import { AppComponent } from './app.component';  
  9. import 'rxjs/Rx';  
  10. import { EmpModule } from './emp/emp.module';  
  11. import { routeConfig } from './app.route-config';  
  12. import { WelcomeComponent } from './welcome/welcome.component';  
  13.   
  14. @NgModule({  
  15.   imports: [BrowserModule, FormsModule, HttpModule, EmpModule, RouterModule.forRoot(routeConfig)],//other modules whose exported classes are needed by component templates declared in this module.  
  16.   declarations: [AppComponent, WelcomeComponent],// the view classes that belong to this module. Angular has three kinds of view classes: components, directives, and pipes.  
  17.   bootstrap: [AppComponent]//the main application view, called the root component, that hosts all other app views. Only the root module should set this bootstrap property.  
  18. })  
  19. export class AppModule { }   

Now, if you try running the application, you’ll find the below snapshot.


If you try to access the welcome page by updating browser’s URL with “/welcome”, you’ll get the below snapshot.



Until now, we were directly updating the browser’s Url to navigate to our View. But in real applications, you’ll be providing the user with menu or links, on clickinf of which the navigation should occur. In Angular2 this could be achieved through RouterLink directive (an inbuilt angular directive). This directive could be applied on links, or for that matter, on any HTML elements on click of which you want navigation to happen. Here is the updated code fragment from app.component.ts file. 

  1. <nav class='navbar navbar-default'>  
  2.     <div class='container-fluid'> <a class='navbar-brand'>{{orgName}}</a>  
  3.         <ul class='nav navbar-nav'>  
  4.             <li><a routerLink="welcome">Home</a></li>  
  5.         </ul>  
  6.     </div>  
  7. </nav>  

NOTE

routerLink value must match the routeConfig path value.

Try refreshing the page and then click on “Home” menu. It should redirect you to the welcome View.

We can also configure the default route for the application as soon as the application starts. For instance, in our application, I want as soon as the application starts user should be redirected to “Home” page. For doing that, I need to configure my route with an empty path. Below is the code snippet for the same:

app.route-config.ts file 

  1. import { Routes } from '@angular/router';  
  2.   
  3. import { WelcomeComponent } from './welcome/welcome.component';  
  4.   
  5. export const routeConfig: Routes = [  
  6.     {  
  7.         path: 'welcome',  
  8.         component: WelcomeComponent  
  9.     },  
  10.     {  
  11.         //default route  
  12.         path: '',  
  13.         component: WelcomeComponent  
  14.     }  
  15. ]   

Try refreshing the page and you’ll be redirected to welcome page by default. Below is the snapshot for the same.


In real applications, we also need to think of those links which are not yet fully published or under maintenance. So, we need a fallback mechanism for handling the user request if the user clicks on any of such links. For instance, let’s assume the “Emp-List” is the link which is under maintenance or not yet published fully & now, if the user clicks on that link, we’ll get an error message in the console screen. Below snapshot describes the same. It clearly tells the root cause for the error “Cannot match any routes”.


In Angular 2, we can provide a fallback mechanism inside our route configuration to handle such scenarios. Below is the updated code snippet for the same.

  1. import { Routes } from '@angular/router';  
  2. import { WelcomeComponent } from './welcome/welcome.component';  
  3.   
  4. export const routeConfig: Routes = [  
  5.     {  
  6.         path: 'welcome',  
  7.         component: WelcomeComponent  
  8.     },  
  9.     {  
  10.         //default route  
  11.         path: '',  
  12.         component: WelcomeComponent  
  13.     },  
  14.     {  
  15.         //fallback mechanism  
  16.         path: '**',  
  17.         component: WelcomeComponent  
  18.     }  
  19. ]   

NOTE

  1. For fallback route we need to use “**” in path
  2. Order of routes matters. Our fallback route path must always be the last route defined inside our route configuration.

Now, if you try running the application on click of “Emp-List” menu, you will be redirected to “Welcome component” & there will be no errors in the console log.

Let’s add route for our new link “Emp-List” which should display employee list component. Below is the updated code snippet for “app.route-config.ts” file.

  1. import { Routes } from '@angular/router';  
  2. import { WelcomeComponent } from './welcome/welcome.component';  
  3. import { EmployeeListComponent } from './emp/emp-list.component'  
  4.   
  5. export const routeConfig: Routes = [  
  6.     {  
  7.         path: 'welcome',  
  8.         component: WelcomeComponent  
  9.     },  
  10.     {  
  11.         path: 'emp-list',  
  12.         component: EmployeeListComponent  
  13.     },  
  14.     {  
  15.         //default route  
  16.         path: '',  
  17.         component: WelcomeComponent  
  18.     },  
  19.     {  
  20.         //fallback mechanism  
  21.         path: '**',  
  22.         component: WelcomeComponent  
  23.     }  
  24. ]   

Now, if you try clicking on the “Emp-List” menu item, it will display EmployeeListComponent in the router outlet. Below is the snapshot for the same.


NOTE

I’ve made some cosmetic changes to the application.

Defining Child routes

A route can have multiple child routes defined as children using the childrens[] array. Even an application can have a single route defined which is acting as the entry route for the application. Let’s suppose we want to navigate to employee details page on click of “EmpId” on EmployeeListComponent, so for achieving this functionality, we need to define child routes. Below is the updated code snippet for the same.

App.route-config.ts 

  1. import { Routes } from '@angular/router';  
  2. import { WelcomeComponent } from './welcome/welcome.component';  
  3. import { EmployeeListComponent } from './emp/emp-list.component'  
  4. import { EmployeeDetailsComponent } from './emp/emp-details.component';  
  5.   
  6. export const routeConfig: Routes = [  
  7.     {  
  8.         path: 'welcome',  
  9.         component: WelcomeComponent  
  10.     },  
  11.     {  
  12.         path: 'emp-list',  
  13.         children: [  
  14.             { path: '', component: EmployeeListComponent },  
  15.             { path: 'emp-details', component: EmployeeDetailsComponent }  
  16.         ]  
  17.     },  
  18.     {  
  19.         //default route  
  20.         path: '',  
  21.         component: WelcomeComponent  
  22.     },  
  23.     {  
  24.         //fallback mechanism  
  25.         path: '**',  
  26.         component: WelcomeComponent  
  27.     }  
  28. ]   

NOTE

  1. I’ve created a path with “emp-list” which is the root for all routes defined inside it as children.
  2. The first path is empty whereby I’m loading the EmployeeListComponent i.e. this is the default route to be loaded
  3. The second path is “emp-details” whereby I’m loading EmployeeDetailsComponent
  4. Also I’ve updated the HTML code for EmployeeListComponent so that our EmployeeId’s are displayed as “hyperlinks”. 
  1. <td class="leftAlign"><a routerLink="emp-details">{{emp.empId}}</a></td>   

If you try running the application, it should be working as expected.


And now, on click of “EmpId”, it should navigate us to “EmployeeDetailsComponent page”. The below snapshot describes the same.


Instead of defining every route in our application root route config file, we can also create feature module specific route config file which will list all routing configuration related to that module. For instance, we can create a new file inside our “emp” folder & store all routing configuration related to “emp” module inside that file. The advantage of doing this is that our application root route config file will be less complex.

I’m adding a new file inside our “emp” folder with the name “emp-route-config.ts”. Below is the snap code for the same:

emp-route-config.ts 

  1. import { Routes } from '@angular/router';  
  2. import { EmployeeListComponent } from './emp-list.component'  
  3. import { EmployeeDetailsComponent } from './emp-details.component';  
  4.   
  5. export const eRoutes: Routes = [  
  6.     {  
  7.         path: 'emp-list',  
  8.         children: [  
  9.             { path: '', component: EmployeeListComponent },  
  10.             {path: 'emp-details', component: EmployeeDetailsComponent }  
  11.         ]  
  12.     }  
  13. ]   

Now, we can include this router configuration inside our application root file using the array spread operator.

app.route-config.ts 

  1. import { Routes } from '@angular/router';  
  2. import { WelcomeComponent } from './welcome/welcome.component';  
  3. import { EmployeeListComponent } from './emp/emp-list.component'  
  4. import { EmployeeDetailsComponent } from './emp/emp-details.component';  
  5. import { eRoutes } from './emp/emp-route.config';  
  6.   
  7. export const routeConfig: Routes = [  
  8.     {  
  9.         path: 'welcome',  
  10.         component: WelcomeComponent  
  11.     },  
  12.     ...eRoutes,  
  13.     {  
  14.         //default route  
  15.         path: '',  
  16.         component: WelcomeComponent  
  17.     },  
  18.     {  
  19.         //fallback mechanism  
  20.         path: '**',  
  21.         component: WelcomeComponent  
  22.     }  
  23. ]   

Try running the application. It will work as expected.


In our next post, we’ll continue further. Until then, you can download the solution and test it locally at your end. I am uploading the solution file with this post; but I won’t be able to upload the node_modules folder because of the heavy size. Thus, I request you to install NPM before you run the application.