How to pass data in angular route component 12 . ?

In previous articles, we have learned, what is routing and how to configure routing in an angular application in detail. In part two on Angular routing, we will learn how to pass data in angular route between components.

When we are building a scalable web application, then we need to send and retrieve data via routing. Let’s generate a couple of components to use for navigation on our previous example of routing articles 1.

ng generate component hotels
ng generate component hotel
ng generate component login 

Navigation within the application: Pass data in Angular route

Angular allows us to navigate between different components mainly using two approaches. First, we can use the router link directive in a template and the second router object in the typescript component. We will demonstrate router navigation using both approaches on the following link.

http://localhost:4200/about
http://localhost:4200/hotels/
http://localhost:4200/hotels/id

We have already created routing.module.ts  and import the routing module in app.module.ts  in the previous example. Edit app-routing.module.ts to add a new routing for hotels and their children routes. We have hotels and its children route with hotels/: id. The slash in a route path is a dynamic value where we are passing hotel id.

import { LoginComponent } from './login/login.component';
import { HotelsComponent } from './hotels/hotels.component';
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AboutComponent } from './about/about.component';
import { NavbarComponent } from './navbar/navbar.component';
import { EditHotelComponent } from './hotels/edit-hotel/edit-hotel.component';
import { HomeComponent } from './home/home.component';


const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'login', component: LoginComponent },
  { path: 'about', component: AboutComponent },
  { path: 'navbar', component: NavbarComponent },
  {
    path: 'hotels', component: HotelsComponent, children: [
      { path: ':id', component: EditHotelComponent }
    ]
  }
];

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

Edit navbar.component.html to include a new route for hotels, login, and hotels/id .

<nav class="navbar navbar-inverse">
    <div class="container">
      <div class="navbar-header">
        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
          <span class="sr-only">Toggle navigation</span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
        </button>
      </div>
      <div id="navbar" class="collapse navbar-collapse">
        <ul class="nav navbar-nav">
          <li><a [routerLink]="['/']">Home</a></li>
          <li><a [routerLink]="['/about']">About</a></li>
          <li><a [routerLink]="['/hotels']">Hotels</a></li>
        </ul>
      </div>
    </div>
  </nav>

We have used routerLink directive in the navbar component to navigating to about and hotels components. The routerLink directive pointing to the path of the component we want to visit. This directive can be applied to any element, although it is typically applied to button and anchor elements

pass data in angular route component

Using a state object of navigate() the method of Angular router object to pass data between components:

Angular allows different ways of passing data between components. We will first learn and demonstrate the state object of navigate() method, this support came since the release of Angular 7.2. We want to send data from home to about components using the state object as shown in the above picture. When a user clicks on the send button in the home component it will call the sendRouteObject () method. This method sends data as an object and navigates to about component.

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

@Component({
  selector: 'app-home',
  template: `
  <div class="container">
    <div class="row">
        <div class="col-md-6">
            <h4>1. In template, route to hotels/id where id is 2</h4>
        </div>
        <div class="col-md-4">
            <button class="btn btn-primary" [routerLink]="['/hotels/' + '2']">Navigation using RouterLink in template</button>
        </div>
    </div>
    <div class="row">
        <div class="col-md-6">
            <h4>2. Programmatically route to hotels with params id </h4>
        </div>
        <div class="col-md-4"> <button class="btn btn-primary" (click)="routeToHotelId(2)">
            Navigation using router object in typescript</button>
        </div>
    </div>
</div>

<div class="mt">
    <h4>3. Send data from search to about component.</h4>
    <p> {{ "{ site: 'edupala.com' frontEnd: { name: Angular version: 12 } }" }}
    </p>
    <button class="btn btn-primary" (click)="sendRouteObject()">Route to aboute component with state data</button>
</div>`,
  styleUrls: ['./home.component.css']
})
export class HomeComponent {

  constructor(private router: Router) { }

  routeToHotelId(id: number) {
    this.router.navigate(['/hotels/' + id]);
  }

  sendRouteObject() {
    this.router.navigate(['/about'], {
      state: {
        frontEnd: JSON.stringify({ framwork: 'Angular', version: '9' }),
        site: 'edupala.com'
      }
    });
  }
}

The navigated method is one of the most used methods of router objects. The navigate takes an argument which is URL to navigate to the new route. We can also pass data via state object in navigate() method. In our example state object, we have two fields, a frontend object which we have to use JSON.stringify, and site as a simple variable we can pass directly.

Reading state object data in navigate() method.

Once we navigate to the requested component. At the activated route component about we can receive data as below and add the following code in the constructor object.

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

@Component({
  selector: 'app-about',
  template: `
  <h4>About works!</h4>
  <div *ngIf="data.frontEnd">
      <p>
        Route state object data from homeomponent:
        <strong>Data: {{ data.frontEnd?.framwork }} - {{ data.frontEnd?.version }} Site: {{ data.site }}</strong>
      </p>
  </div>`,
  styleUrls: ['./about.component.css']
})
export class AboutComponent {
  data: any = {};
  routeState: any;

  constructor(private router: Router) {
    if (this.router.getCurrentNavigation().extras.state) {
      this.routeState = this.router.getCurrentNavigation().extras.state;
      if (this.routeState) {
        this.data.frontEnd = this.routeState.frontEnd ? JSON.parse(this.routeState.frontEnd) : '';
        this.data.site = this.routeState.site ? this.routeState.site : '';
      }
    }
  }
}

Using Route params : To pass data in Angular route

Angular routes can be more flexible and we can pass data parameters to components in the routes as part of the URL path, for example, hotels/:id. Where id is the dynamic value of hotel id of hotel records. To demonstrate route params, let first create a hotel.service.ts class containing dummy hotel records and methods to manage the hotel records.

ng generate service hotels/hotel
import { Injectable } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class HotelService {
  private hotels = [
    { id: 1, name: 'Taj Hotel', country: 'India' },
    { id: 2, name: 'Trump', country: 'United State' },
    { id: 3, name: 'Hotel Oberoi', country: 'India' }
  ];

  getHotels() {
    return this.hotels;
  }

  getHotel(id: number) {
    return this.hotels.find((h: any) => h.id === id);
  }

  updateHotel(id: number, hotelData: { name: string, country: string }) {
    const hotel = this.hotels.find((h) => h.id === id);

    if (hotel) {
      hotel.name = hotelData.name;
      hotel.country = hotelData.country;
    }
  }
}
angular router navigate with params 
pass data in angular route


In the hotels component, we have a list of all hotel records and router-outlet. As the hotels component itself is a child component, we need a nested router-outlet as a place where we render the child element of the hotels component. Edit hotels.component.html file

<table class="table table-striped">
  <thead>
  <tr>
    <th scope="col">#</th>
    <th scope="col">Hotel</th>
    <th scope="col">Country</th>
    <th scope="col">Edit</th>
  </tr>
  </thead>
  <tbody>
  <tr *ngFor="let hotel of hotels; index as i">
    <th scope="row">{{ i + 1 }}</th>
    <td>
      {{ hotel.name }}
    </td>
    <td>{{ hotel.country }}</td>
    <td>
        <button class="btn btn-primary" [routerLink]="['/hotels/' + hotel.id]">Edit</button>
    </td>
  </tr>
  </tbody>
</table>

<div class="col-xs-12 col-sm-4">
    <router-outlet></router-outlet>
</div>

Navigating route with params in a template.

When the user clicks on one of the edit buttons of the hotel record. We will navigate to the hotel component and in the URL path, we will pass the hotel id. Where id is a dynamic value representing hotel id and is pass on navigation URL as params

<button [routerLink]="['/hotels/' + hotel.id]">Edit</button>

Navigating route with params in a component typescript.

When some operation is finished or the user clicked on some button and then we want to trigger the navigation from typescript code. In home.component.html we have a button, which on click will call a method in typescript component, which used a router object method to navigation. The router object has lots of methods, and navigation is the most used one. The navigation first parameter is a path of a component where we want to navigate.

In home.component.html
-----------------------
<button class="btn btn-primary" (click)="routeToHotelId(2)">
   Navigation using router object in typescript</button>
</button>

In home.component.ts
---------------------
routeToHotelId(id: number) {
    this.router.navigate(['/hotels/' + id]);
}

How to retrieve query param from an activated route in a component.

Once we navigate to a component, we have to retrieve query params from the activated route. Angular provides two approaches to retrieve query params at the navigate component.

  • You can read the query parameter from the activatedroute snapshot
  • The activatedRoute query parameters as an observable
import { HotelService } from './../hotel.service';
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, Params } from '@angular/router';

@Component({
  selector: 'app-edit-hotel',
  template: `
  <div *ngIf="hotel">
    <div class="form-group">
        <label for="name">Hotel Name</label>
        <input type="text" id="name" class="form-control" [(ngModel)]="hotel.name">
    </div>
    <div class="form-group">
        <label for="status">Country</label>
        <select id="status" class="form-control" [(ngModel)]="hotel.country">
            <option value="India">India</option>
            <option value="United State">United State</option>
        </select>
    </div>
</div>`,
  styleUrls: ['./edit-hotel.component.css']
})
export class EditHotelComponent implements OnInit {
  hotel: { id: number, name: string, country: string };
  name = '';
  country = '';

  constructor(
    private route: ActivatedRoute,
    private hotelService: HotelService) { }

  ngOnInit() {
    let id = +this.route.snapshot.params['id'];
    this.hotel = this.hotelService.getHotel(id);

    this.route.params.subscribe((params: Params) => {
      id = +params['id'];
      this.hotel = this.hotelService.getHotel(id);
      console.log('hotel' + this.hotel);
    });
    // this.route.paramMap.subscribe((params) => {
    //   id = +params.get('id');
    //   this.hotel = this.hotelService.getHotel(id);
    //   console.log('hotel' + this.hotel);
    // });
  }
}

The snapshot from the ActivatedRoute to read our parameters in the ngOnInit and use when we loaded component it from another component. If we need to load the same component with different parameters in the same component then it is recommended that we do not rely on the snapshot.

As snapshot call once and the only URL will update. Instead, we can treat the parameters and query parameters as observable, just like service calls and HTTP requests. This way, the subscription will get triggered each time the URL changes, allowing us to reload the data rather than relying on the snapshot.

Note: We have comments, instead of param observable, we can use router paramMap observable.

Angular route navigate with paramter using queryParams property

We can also pass optional query parameters using [queryParams] directive along with [routerLink] to pass query parameters in URL.  In URL queryparams with optional parameters, this is indicated by after question marks.

<button [routerLink]="['/hotels', hotel.id]" 
    [queryParams]="{by: 'edupala'}">
    Country detail
</button>
// localhost:8100/hotels/2?by=edupala

// http://localhost:4200/countries/1?by=edupala.com
someMethod(hotel: IHotel) {
   this.router.navigate(['/hotels', hotel.id], 
    {queryParams:{by:'edupala'}});
}

To retrieve optional parameters at routed component use the queryParams observable instead of the params observable of activatedRoute.

 ngOnInit() {
     this.route.queryParams.subscribe( (param.) => {
 	let data = params.by;
     });
 }

Conclusion
We have completed how-to pass data via the Angular route. Use a snapshot to read data from the route object only when we navigate from another component. Snapshot is one time read, not recommend to load the same component with a different parameter. Instead, use params observable to get the latest update value of params from the route object.

Related Articles

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top