Tuesday, August 18, 2020

Nested Route (Child Route) in Angular

All the Angular routing examples we have seen so far have routes that are relative to the root component. But in a big application you would want to contain the route with in another route that is creating routes that are relative to component other than root component. These types of routes with in a route are called nested route or child route in Angular routing.


How to create a child route in Angular routing

You place child routes in a children array within the parent route. For example if you want to create two nested routes relative to ParentComponent then it can be done as follows-

const routes: Routes = [
  {
    path: 'parent',
    component: ParentComponent, 
    children: [
      {
        path: 'child-a',
        component: ChildAComponent
      },
      {
        path: 'child-b',
        component: ChildBComponent
      }
    ]
  }
];

Advantages of using nested routes

1. In a big application you will create a project structure with related functionality classes residing in same folder and sub-folders.

For example if you want to show Account numbers using one component and then individual account details as a separate component then you can have a folder structure like this.

Accounts is the parent folder here having the AccountsComponent and Account is the sub-folder having AccountComponent. Routes for these components can also follow the same parent-child relation, route for AccountComponent can be nested with in the route definition of AccountsComponent.

2. Using child routes also helps in creating better UI where you can display the child route component adjacent to parent route component. For that you need to have a <router-outlet> in the parent component too in addition to the <router-outlet> in AppComponent.

Nested route Angular example

In the Route parameter example we already created this parent-child component folder structure but one problem was clicking the account number to get the account details resulted in a displaying a new component altogether. Now, using child routes we’ll design the application in such a way that account numbers and account details are displayed side-by-side.

1. Routing module

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AccountsComponent } from './accounts/accounts.component';
import { AccountComponent } from './accounts/account/account.component';
import { HomeComponent } from './home.component';
import { ServiceComponent } from './service.component';

const routes: Routes = [
                      {path: 'home', component: HomeComponent},                  
                      {path: 'account', component: AccountsComponent, children: [
                        {path: ':acctno', component: AccountComponent}
                      ]},
                      {path: 'service', component: ServiceComponent},
                      {path: '', redirectTo:'/home', pathMatch: 'full'}             
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

In the Routes array note the child route-

 {path: 'account', component: AccountsComponent, children: [
         {path: ':acctno', component: AccountComponent}
 ]},

In the child route path is in respect to the parent component so you need to specify only path: ':acctno' rather than path: 'account/:acctno'.

app.component.html

This is the template for root component.

<nav class="navbar navbar-expand-md bg-dark navbar-dark">
  <div class="container-fluid">
    <div class="collapse navbar-collapse" id="collapsibleNavbar">
      <ul class="nav navbar-nav">
        <li class="nav-item" routerLinkActive="active">
          <a class="nav-link" routerLink="/home">Home</a>
        </li>
        <li class="nav-item" routerLinkActive="active">
          <a class="nav-link" routerLink="/account">Accounts</a>
        </li>
        <li class="nav-item" routerLinkActive="active">
          <a class="nav-link" [routerLink]="['/service']">Services</a>
        </li>
      </ul>
    </div>
  </div>
</nav>
<div class="container">
  <div class="row"><p></p></div>
  <div class="row">
    <div class="col-md-12">
      <router-outlet></router-outlet>
    </div>
  </div>
</div>

AccountsComponent (accounts.component.ts)

In AccountsComponent there are account numbers stored in an array.

import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-accounts',
  templateUrl: './accounts.component.html'
})
export class AccountsComponent implements OnInit{
  accountnumbers = [];
  constructor(private router: Router, private route: ActivatedRoute) {}
  ngOnInit() {
    this.accountnumbers = ['A1001', 'A1002'];
  }
}

accounts.component.html

This template display the account numbers using ngFor directive and also create a routerLink from each account number.

<div class= "row">
  <div class="col-xs-4 col-md-4">
    <h2>Account Numbers</h2>
    <div class="list-group">
        <a [routerLink]="['/account', accountnumber]"    
         href="#"      
         class="list-group-item"   
         *ngFor="let accountnumber of accountnumbers">
            {{ accountnumber }}
        </a>
    </div>
  </div>
  <div class="col-xs-4 col-md-4">
    <router-outlet></router-outlet>
  </div>
</div>

You can see that this template for AccountsComponent has <router-outlet> too. That’s where the child component is rendered. Since the child route is relative to parent component so where child component is displayed is also the responsibility of parent component.

AccountComponent (account.component.ts)

In this component there are account details stored in an array, account parameter passed as parameter from AccountsComponent is retrieved and the that account number is searched in the array using find method. This task is done using params observable so that once subscribed the logic is executed whenever there is a change in URL.

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params, Router, RouterEvent } from '@angular/router';

@Component({
  selector: 'app-account',
  templateUrl: './account.component.html'
})
export class AccountComponent implements OnInit{
  acctNo: string;
  account: {accountnumber: string, type: string, balance: number};
  constructor(private route: ActivatedRoute, private router: Router){ }
  accountDetails = [
    {
      accountnumber: 'A1001',
      type: 'Saving', 
      balance: 22000
    },
    {
      accountnumber: 'A1002',
      type: 'Checking',
      balance: 1000
    }
  ];

  ngOnInit() {
    this.route.params.subscribe((params: Params)=> {
      this.acctNo = params['acctno'];
      this.account = this.accountDetails.find(e=>e.accountnumber === this.acctNo);});
  }
}

account.component.html

<h2>Account Details</h2>
<div class="row">
  <div class="col-xs-6">
    <label>Account Number: </label> {{ account.accountnumber }}
  </div>
</div>
<div class="row">
  <div class="col-xs-6">
    <label>Account Type: </label> {{ account.type }}
  </div>
</div>
<div class="row">
  <div class="col-xs-6">
    <label>Balance: </label> {{account.balance}}
  </div>
</div>

Add the components and routing module in the declarations array and imports array respectively of the AppModule. After compiling it access the Account page and click on any of the account number.

Child route in Angular
Nested route in Angular example

That's all for this topic Nested Route (Child Route) in Angular. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Angular Tutorial Page


Related Topics

  1. Setting Wild Card Route in Angular
  2. Angular CanActivateChild Guard to protect Child Routes
  3. What is Client Side Routing in Angular
  4. Navigate to a Route Programmatically in Angular
  5. Angular Route Resolver - Passing Data Dynamically

You may also like-

  1. Angular Custom Two-Way Data Binding
  2. Angular ngSwitch Directive With Examples
  3. FormGroup in Angular With Examples
  4. How to Add Bootstrap to Angular Application
  5. PriorityBlockingQueue in Java Concurrency
  6. Difference Between StackOverflowError and OutOfMemoryError in Java
  7. Predefined Mapper And Reducer Classes in Hadoop
  8. Passing Arguments to getBean() Method in Spring

No comments:

Post a Comment