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.
- 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.
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,
- import { Component } from '@angular/core';
-
- @Component({
- selector: 'my-app',
- template: <nav class="navbar navbar-inverse"> <div class='container-fluid'>
- <a class='navbar-brand'>{{orgName}}</a>
- <ul class='nav navbar-nav'>
- <li><a>Home</a></li>
- </ul>
- </div>
- </nav>
- <div class='container'>
- <router-outlet></router-outlet>
- </div>
- </div>`
- })
- export class AppComponent {
- orgName: string = "Angular2 Series";
- }
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.
- import {Routes } from '@angular/router';
- import{WelcomeComponent} from './welcome/welcome.component';
-
- export const routeConfig: Routes = [
- {
- path: 'welcome',
- component: WelcomeComponent
- }
- ]
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.
-
- import { NgModule } from '@angular/core';
- import { FormsModule } from '@angular/forms';
- import { BrowserModule } from '@angular/platform-browser';
- import { HttpModule } from '@angular/http';
- import { RouterModule, Routes } from '@angular/router';
-
- import { AppComponent } from './app.component';
- import 'rxjs/Rx';
- import { EmpModule } from './emp/emp.module';
- import { routeConfig } from './app.route-config';
- import { WelcomeComponent } from './welcome/welcome.component';
-
- @NgModule({
- imports: [BrowserModule, FormsModule, HttpModule, EmpModule, RouterModule.forRoot(routeConfig)],
- declarations: [AppComponent, WelcomeComponent],
- bootstrap: [AppComponent]
- })
- 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.
- <nav class='navbar navbar-default'>
- <div class='container-fluid'> <a class='navbar-brand'>{{orgName}}</a>
- <ul class='nav navbar-nav'>
- <li><a routerLink="welcome">Home</a></li>
- </ul>
- </div>
- </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
- import { Routes } from '@angular/router';
-
- import { WelcomeComponent } from './welcome/welcome.component';
-
- export const routeConfig: Routes = [
- {
- path: 'welcome',
- component: WelcomeComponent
- },
- {
-
- path: '',
- component: WelcomeComponent
- }
- ]
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.
- import { Routes } from '@angular/router';
- import { WelcomeComponent } from './welcome/welcome.component';
-
- export const routeConfig: Routes = [
- {
- path: 'welcome',
- component: WelcomeComponent
- },
- {
-
- path: '',
- component: WelcomeComponent
- },
- {
-
- path: '**',
- component: WelcomeComponent
- }
- ]
NOTE
- For fallback route we need to use “**” in path
- 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.
- import { Routes } from '@angular/router';
- import { WelcomeComponent } from './welcome/welcome.component';
- import { EmployeeListComponent } from './emp/emp-list.component'
-
- export const routeConfig: Routes = [
- {
- path: 'welcome',
- component: WelcomeComponent
- },
- {
- path: 'emp-list',
- component: EmployeeListComponent
- },
- {
-
- path: '',
- component: WelcomeComponent
- },
- {
-
- path: '**',
- component: WelcomeComponent
- }
- ]
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
- import { Routes } from '@angular/router';
- import { WelcomeComponent } from './welcome/welcome.component';
- import { EmployeeListComponent } from './emp/emp-list.component'
- import { EmployeeDetailsComponent } from './emp/emp-details.component';
-
- export const routeConfig: Routes = [
- {
- path: 'welcome',
- component: WelcomeComponent
- },
- {
- path: 'emp-list',
- children: [
- { path: '', component: EmployeeListComponent },
- { path: 'emp-details', component: EmployeeDetailsComponent }
- ]
- },
- {
-
- path: '',
- component: WelcomeComponent
- },
- {
-
- path: '**',
- component: WelcomeComponent
- }
- ]
NOTE
- I’ve created a path with “emp-list” which is the root for all routes defined inside it as children.
- The first path is empty whereby I’m loading the EmployeeListComponent i.e. this is the default route to be loaded
- The second path is “emp-details” whereby I’m loading EmployeeDetailsComponent
- Also I’ve updated the HTML code for EmployeeListComponent so that our EmployeeId’s are displayed as “hyperlinks”.
- <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
- import { Routes } from '@angular/router';
- import { EmployeeListComponent } from './emp-list.component'
- import { EmployeeDetailsComponent } from './emp-details.component';
-
- export const eRoutes: Routes = [
- {
- path: 'emp-list',
- children: [
- { path: '', component: EmployeeListComponent },
- {path: 'emp-details', component: EmployeeDetailsComponent }
- ]
- }
- ]
Now, we can include this router configuration inside our application root file using the array spread operator.
app.route-config.ts
- import { Routes } from '@angular/router';
- import { WelcomeComponent } from './welcome/welcome.component';
- import { EmployeeListComponent } from './emp/emp-list.component'
- import { EmployeeDetailsComponent } from './emp/emp-details.component';
- import { eRoutes } from './emp/emp-route.config';
-
- export const routeConfig: Routes = [
- {
- path: 'welcome',
- component: WelcomeComponent
- },
- ...eRoutes,
- {
-
- path: '',
- component: WelcomeComponent
- },
- {
-
- path: '**',
- component: WelcomeComponent
- }
- ]
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.