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
- localhost:3000/product-details/3/overview
- 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
- localhost:3000/product-list?page=2
Passing Query Parameters
- <a [routerLink]="['product-list']" [queryParams]="{ page: 99 }">Go to Page 99</a>
- goToPage(pageNum) {
-
- this.router.navigate(['/product-list'], { queryParams: { page: pageNum } });
-
- }
Reading Query Parameters
- import { Component } from '@angular/core';
- import { ActivatedRoute, Router } from '@angular/router';
-
- @Component({
- selector: 'product-list',
- template: ``
- })
- export default class ProductList {
- constructor(
- private route: ActivatedRoute,
- private router: Router) {}
-
- ngOnInit() {
- thisthis.sub = this.route
- .queryParams
- .subscribe(params => {
- // Defaults to 0 if no query param provided.
- this.page = +params['page'] || 0;
- });
- }
-
- ngOnDestroy() {
- this.sub.unsubscribe();
- }
-
- nextPage() {
- this.router.navigate(['product-list'], { queryParams: { page: this.page + 1 } });
- }
- }
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
- <div class="panel-body">
- <table class="table table-striped table-bordered">
- <thead>
- <tr>
- <th>Name</th>
- <th>Company</th>
- <th class="text-right">Quantity</th>
- <th class="text-right">Price</th>
- </tr>
- </thead>
- <tbody>
- <tr *ngFor="let item of data">
- <td>{{item.name}}</td>
- <td>{{item.company}}</td>
- <td class="text-right">{{item.quantity}}</td>
- <td class="text-right">{{item.price | currency}}</td>
- </tr>
- </tbody>
- </table>
- </div>
app.component.desktop.ts
- import { Component, OnInit, ViewChild } from '@angular/core';
-
- @Component({
- moduleId: module.id,
- selector: 'desktop',
- templateUrl: 'app.component.desktop.html'
- })
-
- export class DesktopComponent implements OnInit {
-
- private data: Array<any> = [];
-
- constructor() {
- 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' }]
- }
-
- ngOnInit(): void {
- }
-
- }
app.component.laptop.html
- <div class="panel-body">
- <table class="table table-striped table-bordered">
- <thead>
- <tr>
- <th>Name</th>
- <th>Company</th>
- <th class="text-right">Quantity</th>
- <th class="text-right">Price</th>
- </tr>
- </thead>
- <tbody>
- <tr *ngFor="let item of data">
- <td>{{item.name}}</td>
- <td>{{item.company}}</td>
- <td class="text-right">{{item.quantity}}</td>
- <td class="text-right">{{item.price | currency}}</td>
- </tr>
- </tbody>
- </table>
- </div>
app.component.laptop.ts
- import { Component, OnInit, ViewChild } from '@angular/core';
-
- @Component({
- moduleId: module.id,
- selector: 'laptop',
- templateUrl: 'app.component.laptop.html'
- })
-
- export class LaptopComponent implements OnInit {
-
- private data: Array<any> = [];
-
- constructor() {
- this.data = [
- { name: 'Lenovo Flex 2"', company: 'Lenovo', quantity: '20', price: '32000.00', specification: 'Intel Core i3 2 GB Ram 500 GB HDD with DOS OS' },
- { name: 'Lenovo Yova 500"', company: 'Lenovo', quantity: '20', price: '70000.00', specification: 'Intel Core i7 8 GB Ram 1TB HDD with Windows 8.1' }]
- }
-
- ngOnInit(): void {
- }
-
- }
app.component.computer.html
- <div>
- <h2>Computer Details</h2>
- <h3>Special Discount Rate : {{rebate}}</h3>
- <table style="width:20%;">
- <tr class="table-bordered">
- <td><a class="btn-block" (click)="fnNavigateUrl('desktop')">Desktop</a></td>
- <td><a (click)="fnNavigateUrl('laptop')">Laptop</a></td>
- </tr>
- </table>
- <div style="color: red; margin-top: 1rem;">
- Nested Component Route Outlet
- </div>
- <div class="rowDiv navbar-form">
- <router-outlet></router-outlet>
- </div>
- </div>
app.component.computer.ts
- import { Component, OnInit, ViewChild } from '@angular/core';
- import { Router, ActivatedRoute } from '@angular/router';
-
- @Component({
- moduleId: module.id,
- selector: 'computer-details',
- templateUrl: 'app.component.computer.html'
- })
-
- export class ComputerComponent implements OnInit {
-
- private data: Array<any> = [];
- private rebate;
- private sub: any;
-
- constructor(private _router: Router, private route: ActivatedRoute) {
- }
-
- ngOnInit(): void {
- thisthis.sub = this.route.params.subscribe(params => {
- this.rebate = +params['id'];
- });
- }
-
- private fnNavigateUrl(key: string): void {
- this._router.navigate(['/computer/' + key]);
- }
-
- private ngOnDestroy() {
- this.sub.unsubscribe();
- }
- }
app.component.mobile.html
- <div class="panel-body">
- <table class="table table-striped table-bordered">
- <thead>
- <tr>
- <th>Name</th>
- <th>Company</th>
- <th class="text-right">Quantity</th>
- <th class="text-right">Price</th>
- </tr>
- </thead>
- <tbody>
- <tr *ngFor="let item of data">
- <td>{{item.name}}</td>
- <td>{{item.company}}</td>
- <td class="text-right">{{item.quantity}}</td>
- <td class="text-right">{{item.price |currency:'INR':true}}</td>
- </tr>
- </tbody>
- </table>
- </div>
app.component.mobile.ts
- import { Component, OnInit, ViewChild } from '@angular/core';
-
- @Component({
- moduleId: module.id,
- selector: 'mobile',
- templateUrl: 'app.component.mobile.html'
- })
-
- export class MobileComponent implements OnInit {
-
- private data: Array<any> = [];
-
- constructor() {
- this.data = [{ name: 'Galaxy Tab 3', company: 'Samsung', quantity: '10', price: '25000.00' },
- { name: 'Galaxy Tab 5', company: 'Samsung', quantity: '50', price: '55000.00' },
- { name: 'G4', company: 'LG', quantity: '10', price: '40000.00' },
- { name: 'Canvas 3', company: 'Micromax', quantity: '25', price: '18000.00' }];
- }
-
- ngOnInit(): void {
- }
-
- }
app.component.tv.html
- <div class="panel-body">
- <table class="table table-striped table-bordered">
- <thead>
- <tr>
- <th>Name</th>
- <th>Company</th>
- <th class="text-right">Quantity</th>
- <th class="text-right">Price</th>
- </tr>
- </thead>
- <tbody>
- <tr *ngFor="let item of data">
- <td>{{item.name}}</td>
- <td>{{item.company}}</td>
- <td class="text-right">{{item.quantity}}</td>
- <td class="text-right">{{item.price | currency}}</td>
- </tr>
- </tbody>
- </table>
- </div>
app.component.tv.ts
- import { Component, OnInit, ViewChild } from '@angular/core';
-
- @Component({
- moduleId: module.id,
- selector: 'tv',
- templateUrl: 'app.component.tv.html'
- })
-
- export class TvComponent implements OnInit {
-
- private data: Array<any> = [];
-
- constructor() {
- this.data = [{ name: 'LED TV 20"', company: 'Samsung', quantity: '10', price: '11000.00' },
- { name: 'LED TV 24"', company: 'Samsung', quantity: '50', price: '15000.00' },
- { name: 'LED TV 32"', company: 'LG', quantity: '10', price: '32000.00' },
- { name: 'LED TV 48"', company: 'SONY', quantity: '25', price: '28000.00' }];
- }
-
- ngOnInit(): void {
- }
-
- }
app.component.home.html
- <div class="row">
- <div class="panel-body">
- Home Page
- <br />
- <h3 class="panel-heading"><span>{{message}}</span></h3>
- </div>
- </div>
app.component.home.ts
- import { Component, OnInit, ViewChild } from '@angular/core';
-
- @Component({
- moduleId: module.id,
- selector: 'home',
- templateUrl: 'app.component.home.html'
- })
-
- export class HomeComponent implements OnInit {
-
- private message: string = '';
- constructor() {
- this.message = 'Click link to move other page';
- }
-
- ngOnInit(): void {
- }
-
- }
app.component.homepage.html
- <div class="rowDiv panel panel-primary">
- <h2 class="panel-heading">Demostration of Angular 2.0 Basic Route</h2>
- <table style="width:40%;">
- <tr class="table-bordered">
- <td><a class="btn-block" (click)="fnNavigateUrl('home')">Home</a></td>
- <td><a (click)="fnNavigateUrl('mobile')">Mobile</a></td>
- <td><a (click)="fnNavigateUrl('tv')">TV</a></td>
- <td><a (click)="fnNavigateUrl('computer')">Computers</a></td>
- </tr>
- </table>
- </div>
- <div class="rowDiv navbar-form">
- <router-outlet></router-outlet>
- </div>
app.component.homepage.ts
- import { Component, OnInit, ViewChild } from '@angular/core';
- import { Router } from '@angular/router';
-
- @Component({
- moduleId: module.id,
- selector: 'home-page',
- templateUrl: 'app.component.homepage.html'
- })
-
- export class HomePageComponent implements OnInit {
-
- constructor(private _router: Router) {
- }
-
- ngOnInit(): void {
- }
-
- private fnNavigateUrl(key: string): void {
- if (key == 'computer') {
- this._router.navigate(['/' + key, 10]);
- }
- else
- this._router.navigate(['/' + key]);
- }
- }
app.routes.ts
- import { Routes, RouterModule } from '@angular/router';
- import { HomeComponent } from './app.component.home';
- import { MobileComponent } from './app.component.mobile';
- import { TvComponent } from './app.component.tv';
- import { ComputerComponent } from './app.component.computer';
- import { DesktopComponent } from './app.component.desktop';
- import { LaptopComponent } from './app.component.laptop';
-
- export const routes: Routes = [
- { path: '', redirectTo: 'home', pathMatch: 'full' },
- { path: 'home', component: HomeComponent },
- { path: 'tv', component: TvComponent },
- { path: 'mobile', component: MobileComponent },
- {
- path: 'computer/:id', component: ComputerComponent,
- children: [
- { path: '', redirectTo: 'computer/laptop', pathMatch: 'full' },
- { path: 'computer/desktop', component: DesktopComponent },
- { path: 'computer/laptop', component: LaptopComponent }
- ]
- }
- ];
-
- export const appRoutingProviders: any[] = [
-
- ];
-
- export const routing = RouterModule.forRoot(routes);
app.module.ts
- import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
- import { BrowserModule } from '@angular/platform-browser';
- import { FormsModule } from "@angular/forms";
-
- import { routing, appRoutingProviders } from './src/app.routes';
- import { HomePageComponent } from './src/app.component.homepage';
- import { HomeComponent } from './src/app.component.home';
- import { MobileComponent } from './src/app.component.mobile';
- import { TvComponent } from './src/app.component.tv';
- import { ComputerComponent } from './src/app.component.computer';
- import { DesktopComponent } from './src/app.component.desktop';
- import { LaptopComponent } from './src/app.component.laptop';
-
- @NgModule({
- imports: [BrowserModule, FormsModule, routing],
- declarations: [HomePageComponent, HomeComponent, MobileComponent, TvComponent, ComputerComponent, DesktopComponent, LaptopComponent],
- bootstrap: [HomePageComponent],
- schemas: [NO_ERRORS_SCHEMA],
- providers: [appRoutingProviders],
- })
- export class AppModule { }
main.ts
- import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
-
- import { AppModule } from './app.module';
-
- const platform = platformBrowserDynamic();
- platform.bootstrapModule(AppModule);
index.html
- <!DOCTYPE html>
- <html>
- <head>
- <title>Angular2 - Advanced router example</title>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <link href="../resources/style/bootstrap.css" rel="stylesheet" />
- <link href="../resources/style/style1.css" rel="stylesheet" />
-
- <script src="../resources/js/jquery-2.1.1.js"></script>
- <script src="../resources/js/bootstrap.js"></script>
-
- <script src="../node_modules/core-js/client/shim.min.js"></script>
- <script src="../node_modules/zone.js/dist/zone.js"></script>
- <script src="../node_modules/reflect-metadata/Reflect.js"></script>
- <script src="../node_modules/systemjs/dist/system.src.js"></script>
- <script src="../systemjs.config.js"></script>
- <script>
- System.import('app').catch(function (err) { console.error(err); });
- </script>
-
- <script>document.write('<base href="' + document.location + '" />');</script>
- </head>
- <body>
- <home-page>Loading</home-page>
- </body>
- </html>
The output of the above code is shown below.