AngularJS 2.0 From The Beginning - Route Part Two - Day Fourteen

I am here to continue the discussion around AngularJS 2.0. So far, we have discussed about data binding, input properties, output properties, pipes, viewchild, directives, and services including basic routes in Angular 2.0. Now in this article, I will discuss how to pass parameters within routes and also nested routes in Angular 2.0. In case you did not have a look at the previous articles of this series, go through the links mentioned below.

In my previous article, I already discussed about the basic route in Angular 2.0. Now in this article, we discuss about the child route or nested route in Angular 2.0.

What is Nested Child Routes?

Child/Nested routing is a powerful new feature in the new Angular router. We can think of our application as a tree structure, components nested in more components. We can think the same way with our routes and URLs.

So, we have the following routes, / and /about. Maybe our about page is extensive and there are a couple of different views we would like to display as well. The URLs would look something like /about and /about/ item. The first route would be the default about page but more routes would offer another view with more details.

Defining Child Routes

When some routes are only be accessible and viewed within other routes, it may be appropriate to create them as child routes.

For example -

The product details page may have a tabbed navigation section that shows the product overview by default. When the user clicks the "Technical Specs" tab, the section shows the specs instead.

If the user clicks on the product with ID 3, we want to show the product details page with the overview.

  1. localhost:3000/product-details/3/overview  

When the user clicks "Technical Specs",

  1. localhost:3000/product-details/3/specs  

Overview and specs are child routes of product-details/:id. They are only reachable within product details.

Passing Optional Parameters

Query parameters allow you to pass optional parameters to a route, such as pagination information.

For example, on a route with a paginated list, the URL might look like the following to indicate that we've loaded the second page.

  1. localhost:3000/product-list?page=2 

The key difference between query parameters and route parameters is that route parameters are essential to determine route whereas query parameters are optional.

Passing Query Parameters

Use the [queryParams] directive along with [routerLink] to pass query parameters. For example,

  1. <a [routerLink]="['product-list']" [queryParams]="{ page: 99 }">Go to Page 99</a> 

Alternatively, we can navigate programmatically using the Router Service.

  1. goToPage(pageNum) {  
  2.   
  3.  this.router.navigate(['/product-list'], { queryParams: { page: pageNum } });  
  4.   
  5.  } 

Reading Query Parameters

Similar to reading route parameters, the Router service returns an Observable we can subscribe to to read the query parameters.

  1. import { Component } from '@angular/core';  
  2. import { ActivatedRoute, Router } from '@angular/router';  
  3.   
  4. @Component({  
  5.   selector: 'product-list',  
  6.   template: `<!-- Show product list -->`  
  7. })  
  8. export default class ProductList {  
  9.   constructor(  
  10.     private route: ActivatedRoute,  
  11.     private router: Router) {}  
  12.   
  13.   ngOnInit() {  
  14.     thisthis.sub = this.route  
  15.       .queryParams  
  16.       .subscribe(params => {  
  17.         // Defaults to 0 if no query param provided.  
  18.         this.page = +params['page'] || 0;  
  19.       });  
  20.   }  
  21.   
  22.   ngOnDestroy() {  
  23.     this.sub.unsubscribe();  
  24.   }  
  25.   
  26.   nextPage() {  
  27.     this.router.navigate(['product-list'], { queryParams: { page: this.page + 1 } });  
  28.   }  

For demonstrating this concept, we simply replicate the program of the previous article. Here, we change one thing, that is, 
computer component will contain two more sub components called desktop and laptop which will be loaded via child route concept.

For doing this, we need to add the following files.

app.component.desktop.html
  1. <div class="panel-body">  
  2.     <table class="table table-striped table-bordered">  
  3.         <thead>  
  4.             <tr>  
  5.                 <th>Name</th>  
  6.                 <th>Company</th>  
  7.                 <th class="text-right">Quantity</th>  
  8.                 <th class="text-right">Price</th>  
  9.             </tr>  
  10.         </thead>  
  11.         <tbody>  
  12.             <tr *ngFor="let item of data">  
  13.                 <td>{{item.name}}</td>  
  14.                 <td>{{item.company}}</td>  
  15.                 <td class="text-right">{{item.quantity}}</td>  
  16.                 <td class="text-right">{{item.price | currency}}</td>  
  17.             </tr>  
  18.         </tbody>  
  19.     </table>  
  20. </div>  
app.component.desktop.ts
  1. import { Component, OnInit, ViewChild } from '@angular/core';  
  2.   
  3. @Component({  
  4.     moduleId: module.id,  
  5.     selector: 'desktop',  
  6.     templateUrl: 'app.component.desktop.html'  
  7. })  
  8.   
  9. export class DesktopComponent implements OnInit {  
  10.   
  11.     private data: Array<any> = [];  
  12.   
  13.     constructor() {  
  14.         this.data = [{ name: 'HP Pavilion 15"', company: 'HP', quantity: '10', price: '42000.00', specification: 'Intel Core i3 2 GB Ram 500 GB HDD with Windows 10' }]  
  15.     }  
  16.   
  17.     ngOnInit(): void {  
  18.     }  
  19.   
  20. }   
app.component.laptop.html
  1. <div class="panel-body">  
  2.     <table class="table table-striped table-bordered">  
  3.         <thead>  
  4.             <tr>  
  5.                 <th>Name</th>  
  6.                 <th>Company</th>  
  7.                 <th class="text-right">Quantity</th>  
  8.                 <th class="text-right">Price</th>  
  9.             </tr>  
  10.         </thead>  
  11.         <tbody>  
  12.             <tr *ngFor="let item of data">  
  13.                 <td>{{item.name}}</td>  
  14.                 <td>{{item.company}}</td>  
  15.                 <td class="text-right">{{item.quantity}}</td>  
  16.                 <td class="text-right">{{item.price | currency}}</td>  
  17.             </tr>  
  18.         </tbody>  
  19.     </table>  
  20. </div> 
 
app.component.laptop.ts
  1. import { Component, OnInit, ViewChild } from '@angular/core';  
  2.   
  3. @Component({  
  4.     moduleId: module.id,  
  5.     selector: 'laptop',  
  6.     templateUrl: 'app.component.laptop.html'  
  7. })  
  8.   
  9. export class LaptopComponent implements OnInit {  
  10.   
  11.     private data: Array<any> = [];  
  12.   
  13.     constructor() {  
  14.         this.data = [  
  15.         { name: 'Lenovo Flex 2"', company: 'Lenovo', quantity: '20', price: '32000.00', specification: 'Intel Core i3 2 GB Ram 500 GB HDD with DOS OS' },  
  16.         { name: 'Lenovo Yova 500"', company: 'Lenovo', quantity: '20', price: '70000.00', specification: 'Intel Core i7 8 GB Ram 1TB HDD with Windows 8.1' }]  
  17.     }  
  18.   
  19.     ngOnInit(): void {  
  20.     }  
  21.   

app.component.computer.html
  1. <div>  
  2.     <h2>Computer Details</h2>  
  3.     <h3>Special Discount Rate : {{rebate}}</h3>  
  4.     <table style="width:20%;">  
  5.         <tr class="table-bordered">  
  6.             <td><a class="btn-block" (click)="fnNavigateUrl('desktop')">Desktop</a></td>  
  7.             <td><a (click)="fnNavigateUrl('laptop')">Laptop</a></td>  
  8.         </tr>  
  9.     </table>  
  10.     <div style="color: red; margin-top: 1rem;">  
  11.        Nested Component Route Outlet  
  12.     </div>     
  13.     <div class="rowDiv navbar-form">  
  14.         <router-outlet></router-outlet>  
  15.     </div>    
  16. </div> 
app.component.computer.ts
  1. import { Component, OnInit, ViewChild } from '@angular/core';  
  2. import { Router, ActivatedRoute } from '@angular/router';  
  3.   
  4. @Component({  
  5.     moduleId: module.id,  
  6.     selector: 'computer-details',  
  7.     templateUrl: 'app.component.computer.html'  
  8. })  
  9.   
  10. export class ComputerComponent implements OnInit {  
  11.   
  12.     private data: Array<any> = [];  
  13.     private rebate;  
  14.     private sub: any;  
  15.   
  16.     constructor(private _router: Router, private route: ActivatedRoute) {         
  17.     }  
  18.   
  19.     ngOnInit(): void {  
  20.         thisthis.sub = this.route.params.subscribe(params => {  
  21.             this.rebate = +params['id'];   
  22.         });  
  23.     }  
  24.   
  25.     private fnNavigateUrl(key: string): void {  
  26.         this._router.navigate(['/computer/' + key]);  
  27.     }  
  28.   
  29.     private ngOnDestroy() {  
  30.         this.sub.unsubscribe();  
  31.     }  

app.component.mobile.html
  1. <div class="panel-body">  
  2.     <table class="table table-striped table-bordered">  
  3.         <thead>  
  4.             <tr>  
  5.                 <th>Name</th>  
  6.                 <th>Company</th>  
  7.                 <th class="text-right">Quantity</th>  
  8.                 <th class="text-right">Price</th>  
  9.             </tr>  
  10.         </thead>  
  11.         <tbody>  
  12.             <tr *ngFor="let item of data">  
  13.                 <td>{{item.name}}</td>  
  14.                 <td>{{item.company}}</td>  
  15.                 <td class="text-right">{{item.quantity}}</td>  
  16.                 <td class="text-right">{{item.price |currency:'INR':true}}</td>  
  17.             </tr>  
  18.         </tbody>  
  19.     </table>  
  20. </div> 
app.component.mobile.ts
  1. import { Component, OnInit, ViewChild } from '@angular/core';  
  2.   
  3. @Component({  
  4.     moduleId: module.id,  
  5.     selector: 'mobile',  
  6.     templateUrl: 'app.component.mobile.html'  
  7. })  
  8.   
  9. export class MobileComponent implements OnInit {  
  10.   
  11.     private data: Array<any> = [];  
  12.   
  13.     constructor() {  
  14.         this.data = [{ name: 'Galaxy Tab 3', company: 'Samsung', quantity: '10', price: '25000.00' },  
  15.         { name: 'Galaxy Tab 5', company: 'Samsung', quantity: '50', price: '55000.00' },  
  16.         { name: 'G4', company: 'LG', quantity: '10', price: '40000.00' },  
  17.         { name: 'Canvas 3', company: 'Micromax', quantity: '25', price: '18000.00' }];  
  18.     }  
  19.   
  20.     ngOnInit(): void {  
  21.     }  
  22.   

app.component.tv.html
  1. <div class="panel-body">  
  2.     <table class="table table-striped table-bordered">  
  3.         <thead>  
  4.             <tr>  
  5.                 <th>Name</th>  
  6.                 <th>Company</th>  
  7.                 <th class="text-right">Quantity</th>  
  8.                 <th class="text-right">Price</th>  
  9.             </tr>  
  10.         </thead>  
  11.         <tbody>  
  12.             <tr *ngFor="let item of data">  
  13.                 <td>{{item.name}}</td>  
  14.                 <td>{{item.company}}</td>  
  15.                 <td class="text-right">{{item.quantity}}</td>  
  16.                 <td class="text-right">{{item.price | currency}}</td>  
  17.             </tr>  
  18.         </tbody>  
  19.     </table>  
  20. </div> 
app.component.tv.ts
  1. import { Component, OnInit, ViewChild } from '@angular/core';  
  2.   
  3. @Component({  
  4.     moduleId: module.id,  
  5.     selector: 'tv',  
  6.     templateUrl: 'app.component.tv.html'  
  7. })  
  8.   
  9. export class TvComponent implements OnInit {  
  10.   
  11.     private data: Array<any> = [];  
  12.   
  13.     constructor() {  
  14.         this.data = [{ name: 'LED TV 20"', company: 'Samsung', quantity: '10', price: '11000.00' },  
  15.         { name: 'LED TV 24"', company: 'Samsung', quantity: '50', price: '15000.00' },  
  16.         { name: 'LED TV 32"', company: 'LG', quantity: '10', price: '32000.00' },  
  17.         { name: 'LED TV 48"', company: 'SONY', quantity: '25', price: '28000.00' }];  
  18.     }  
  19.   
  20.     ngOnInit(): void {  
  21.     }  
  22.   
  23. }   
app.component.home.html
  1. <div class="row">  
  2.     <div class="panel-body">  
  3.         Home Page  
  4.         <br />  
  5.         <h3 class="panel-heading"><span>{{message}}</span></h3>  
  6.     </div>  
  7. </div>  
app.component.home.ts
  1. import { Component, OnInit, ViewChild } from '@angular/core';  
  2.   
  3. @Component({  
  4.     moduleId: module.id,  
  5.     selector: 'home',  
  6.     templateUrl: 'app.component.home.html'  
  7. })  
  8.   
  9. export class HomeComponent implements OnInit {  
  10.   
  11.     private message: string = '';  
  12.     constructor() {  
  13.         this.message = 'Click link to move other page';  
  14.     }  
  15.   
  16.     ngOnInit(): void {  
  17.     }  
  18.   

app.component.homepage.html
  1. <div class="rowDiv panel panel-primary">  
  2.     <h2 class="panel-heading">Demostration of Angular 2.0 Basic Route</h2>  
  3.     <table style="width:40%;">  
  4.         <tr class="table-bordered">  
  5.             <td><a class="btn-block" (click)="fnNavigateUrl('home')">Home</a></td>  
  6.             <td><a (click)="fnNavigateUrl('mobile')">Mobile</a></td>  
  7.             <td><a (click)="fnNavigateUrl('tv')">TV</a></td>  
  8.             <td><a (click)="fnNavigateUrl('computer')">Computers</a></td>  
  9.         </tr>  
  10.     </table>  
  11. </div>  
  12. <div class="rowDiv navbar-form">  
  13.     <router-outlet></router-outlet>  
  14. </div>      
app.component.homepage.ts
  1. import { Component, OnInit, ViewChild } from '@angular/core';  
  2. import { Router } from '@angular/router';  
  3.   
  4. @Component({  
  5.     moduleId: module.id,  
  6.     selector: 'home-page',  
  7.     templateUrl: 'app.component.homepage.html'  
  8. })  
  9.   
  10. export class HomePageComponent implements OnInit {  
  11.   
  12.     constructor(private _router: Router) {  
  13.     }  
  14.   
  15.     ngOnInit(): void {  
  16.     }  
  17.   
  18.     private fnNavigateUrl(key: string): void {  
  19.         if (key == 'computer') {  
  20.             this._router.navigate(['/' + key, 10]);  
  21.         }  
  22.         else  
  23.             this._router.navigate(['/' + key]);  
  24.     }  

app.routes.ts
  1. import { Routes, RouterModule } from '@angular/router';  
  2. import { HomeComponent } from './app.component.home';  
  3. import { MobileComponent } from './app.component.mobile';  
  4. import { TvComponent } from './app.component.tv';  
  5. import { ComputerComponent } from './app.component.computer';  
  6. import { DesktopComponent } from './app.component.desktop';  
  7. import { LaptopComponent } from './app.component.laptop';  
  8.   
  9. export const routes: Routes = [  
  10.     { path: '', redirectTo: 'home', pathMatch: 'full' },  
  11.     { path: 'home', component: HomeComponent },  
  12.     { path: 'tv', component: TvComponent },  
  13.     { path: 'mobile', component: MobileComponent },  
  14.     {  
  15.         path: 'computer/:id', component: ComputerComponent,  
  16.         children: [  
  17.             { path: '', redirectTo: 'computer/laptop', pathMatch: 'full' },  
  18.             { path: 'computer/desktop', component: DesktopComponent },  
  19.             { path: 'computer/laptop', component: LaptopComponent }  
  20.         ]  
  21.     }  
  22. ];  
  23.   
  24. export const appRoutingProviders: any[] = [  
  25.   
  26. ];  
  27.   
  28. export const routing = RouterModule.forRoot(routes); 
app.module.ts
  1. import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';  
  2. import { BrowserModule } from '@angular/platform-browser';  
  3. import { FormsModule } from "@angular/forms";  
  4.   
  5. import { routing, appRoutingProviders } from './src/app.routes';  
  6. import { HomePageComponent } from './src/app.component.homepage';  
  7. import { HomeComponent } from './src/app.component.home';  
  8. import { MobileComponent } from './src/app.component.mobile';  
  9. import { TvComponent } from './src/app.component.tv';  
  10. import { ComputerComponent } from './src/app.component.computer';  
  11. import { DesktopComponent } from './src/app.component.desktop';  
  12. import { LaptopComponent } from './src/app.component.laptop';  
  13.   
  14. @NgModule({  
  15.     imports: [BrowserModule, FormsModule, routing],  
  16.     declarations: [HomePageComponent, HomeComponent, MobileComponent, TvComponent, ComputerComponent, DesktopComponent, LaptopComponent],  
  17.     bootstrap: [HomePageComponent],  
  18.     schemas: [NO_ERRORS_SCHEMA],  
  19.     providers: [appRoutingProviders],  
  20. })  
  21. export class AppModule { } 
main.ts
  1. import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';  
  2.   
  3. import { AppModule } from './app.module';  
  4.   
  5. const platform = platformBrowserDynamic();  
  6. platform.bootstrapModule(AppModule); 
index.html
  1. <!DOCTYPE html>  
  2. <html>  
  3. <head>  
  4.     <title>Angular2 - Advanced router example</title>  
  5.     <meta charset="UTF-8">  
  6.     <meta name="viewport" content="width=device-width, initial-scale=1">  
  7.     <link href="../resources/style/bootstrap.css" rel="stylesheet" />  
  8.     <link href="../resources/style/style1.css" rel="stylesheet" />  
  9.     <!-- Polyfill(s) for older browsers -->  
  10.     <script src="../resources/js/jquery-2.1.1.js"></script>  
  11.     <script src="../resources/js/bootstrap.js"></script>  
  12.   
  13.     <script src="../node_modules/core-js/client/shim.min.js"></script>  
  14.     <script src="../node_modules/zone.js/dist/zone.js"></script>  
  15.     <script src="../node_modules/reflect-metadata/Reflect.js"></script>  
  16.     <script src="../node_modules/systemjs/dist/system.src.js"></script>  
  17.     <script src="../systemjs.config.js"></script>  
  18.     <script>  
  19.         System.import('app').catch(function (err) { console.error(err); });  
  20.     </script>  
  21.     <!-- Set the base href, demo only! In your app: <base href="/"> -->  
  22.     <script>document.write('<base href="' + document.location + '" />');</script>  
  23. </head>  
  24. <body>  
  25.     <home-page>Loading</home-page>  
  26. </body>  
  27. </html> 
The output of the above code is shown below.