Angular 6 Routing/Navigation – with Angular Router Service

Angular 6 Routing_Navigation – with Angular Router Service

In Angular application, how to navigation among views? Developers can achieve it with the power of Angular Router Service that helps find out a corresponding Route when having any changes of browser’s URL to determine the component to display.

Related posts:
Integrate Bootstrap with Angular
Angular 6 Service – with Observable Data for Asynchronous Operation
Angular 6 Component – How to create & integrate New Angular 6 Component
Angular 6 dynamic Navigation Bar – add/remove Route dynamically

Technologies

  • Node.js – version v10.4.0
  • Angular – version 6
  • Bootstrap – 3.x & 4.x
  • Visual Studio Code – version 1.24.0

Goal

We create an Angular project as below:

angular-6-routing + angular-project-structure

-> Navigation:

– Home Page (also US Customer Component page):

– UK Customer Component page:

angular-6-routing + uk - customer

– Details Customer page:

angular-6-routing + a-customer-view-routing

– Press go Back button:

angular-6-routing + go back

Application provides a list URLs as below:

  • http://localhost:4200/
  • http://localhost:4200/customers-us
  • http://localhost:4200/customers-uk
  • http://localhost:4200/customers/:id

How to navigate among these views?

– When enter in browser address bar: http://localhost:4200 or http://localhost:4200/customers-us, the app will always redirect to http://localhost:4200/customers-us that be served by CustomerUSComponent.
– When click on each customer item’s link in CustomerUsComponent or CustomerUkComponent views, or enter the links http://localhost:4200/customers/:id in browser address bar -> The browser will show CustomerDetailComponent view with the Browser’s URL http://localhost:4200/customers/{id}.
– Press on Back button, the browser’s URL will be backed one step.

When press other URLs, PageNotFound will be appeared:

angular-6-routing + wrong-url

Angular Router

Angular project preparation

– Generate Angular project:

angular-6-routing + create-angular-project

– Generate:

  • 4 Components {CustomerUsComponent, CustomerUkComponent, CustomerDetailComponent, PageNotFoundComponent}
  • Data Service: CustomerService
  • Module: AppRoutingModule
  • Class: Customer

angular-6-routing + create-angular-generate-components-service-app-routing

– Install Bootstrap 4:

npm install bootstrap jquery --save

-> Configure installed Bootstrap & JQuery in angular.json file:

...
 
"styles": [
  "src/styles.css",
  "node_modules/bootstrap/dist/css/bootstrap.min.css"
],
"scripts": [
  "node_modules/jquery/dist/jquery.min.js",
  "node_modules/bootstrap/dist/js/bootstrap.min.js"
]
 
...

Angular Router

Angular Routing Module

In the AppRoutingModule file, configure routes as below:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { RouterModule, Routes } from '@angular/router';

import { CustomerUsComponent } from '../customer-us/customer-us.component';
import { CustomerUkComponent } from '../customer-uk/customer-uk.component';
import { CustomerDetailComponent } from '../customer-detail/customer-detail.component';
import { PageNotFoundComponent } from '../page-not-found/page-not-found.component'

const routes: Routes = [
  { 
    path: 'customers-us', 
    component: CustomerUsComponent 
  },
  { 
    path: 'customers-uk', 
    component: CustomerUkComponent 
  },
  { 
    path: 'customers/:id',
    component: CustomerDetailComponent 
  },
  { 
    path: '',
    redirectTo: '/customers-us',
    pathMatch: 'full'
  },
  { 
    path: '**',
    component: PageNotFoundComponent 
  }
];

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

routes array of routes describes how to navigate.
– Each Route maps a URL path to a component.
– The :id in the second route is a token for a route parameter.

Register AppRoutingModule with AppModule:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { CustomerUsComponent } from './customer-us/customer-us.component';
import { CustomerUkComponent } from './customer-uk/customer-uk.component';
import { CustomerDetailComponent } from './customer-detail/customer-detail.component';
import { PageNotFoundComponent } from './page-not-found/page-not-found.component';

import { AppRoutingModule } from './app-routing/app-routing.module';

@NgModule({
  declarations: [
    AppComponent,
    CustomerUsComponent,
    CustomerUkComponent,
    CustomerDetailComponent,
    PageNotFoundComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Router Outlet & Router Links

Questions:

  • How to show Componenets with Angular Routers? -> Solution: using Router Outlet
  • How to handle the routing that comes from user’s actions? (like clicks on anchor tag) -> Solution: using Router Link

-> We can achieve above functions by using Angular’s router-outlet and routerLink.

Now modify the template file app.component.html of parent AppComponenet component as below:

<div class="container">
<div class="row">
  <div class="col-sm-4">
    <h2>Angular Router</h2>

    <ul class="nav">
        <li class="nav-item">
            <a routerLink="customers-us" routerLinkActive="active" class="btn btn-light" role="button">US-Customers</a>
        </li>
        <li class="nav-item">
            <a routerLink ="customers-uk" routerLinkActive="active" class="btn btn-light" role="button">UK-Customers</a>
        </li>
    </ul>
    <hr>
    <router-outlet></router-outlet>
  </div>
</div>
</div>

The RouterLinkActive directive is used to visual the anchor tag for the currently selected “active” route.
Now these components {CustomerUsComponent, CustomerUKComponent, CustomerDetailComponent, PageNotFoundComponent} will be showed under router-outlet tag.

We already had done to setup Routing configuration. -> It’s time for developement Data Service & view-Components.

Data Services implementation

Customer Data Model

Code for customer.ts class:

export class Customer {
    constructor(public id: number, 
                public firstname: string, 
                public lastname:string,
                public nationality: string) { }
}

Customer Service

import { Injectable } from '@angular/core';
import { of } from 'rxjs';
import { map, filter } from 'rxjs/operators';

import { Customer } from './customer'
import { filterQueryId } from '@angular/core/src/view/util';

const CUSTOMERS = [
  {id: 1, firstname: 'Mary', lastname: 'Taylor', age: 24, nationality: 'US'},
  {id: 2, firstname: 'Peter', lastname: 'Smith', age: 18, nationality: 'UK'},
  {id: 3, firstname: 'Lauren', lastname: 'Taylor', age: 31, nationality: 'UK'},
  {id: 4, firstname: 'Michael', lastname: 'Brown', age: 45, nationality: 'US'},
  {id: 5, firstname: 'David', lastname: 'Moore', age: 25, nationality: 'US'},
  {id: 6, firstname: 'Holly', lastname: 'Davies', age: 27, nationality: 'UK'},
  {id: 7, firstname: 'Joe', lastname: 'Thomas', age: 36, nationality: 'UK'},
];


@Injectable({
  providedIn: 'root'
})
export class CustomerService {

  constructor() { }
}

@Injectable()
export class HeroService {
  getCustomers() { return of(CUSTOMERS); }

  getCustomer(id: number | string) {
    return this.getCustomers().pipe(
      // (+) before `id` turns the string into a number
      map(customers => customers.find(customer => customer.id === +id))
    );
  }

  getCustomersByNationality(nationality: string){
    return this.getCustomers().pipe(
      map(customers => customers.filter(cust => cust.nationality === nationality))
    )
  }
}

Angular Components implementation

Customer US Component

– Implement customer-us.component.ts class:

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

import { Observable } from 'rxjs';

import { Customer } from '../customer'
import { CustomerService} from '../customer.service'

@Component({
  selector: 'app-customer-us',
  templateUrl: './customer-us.component.html',
  styleUrls: ['./customer-us.component.css']
})
export class CustomerUsComponent implements OnInit {

  customers$: Observable;

  constructor(private service: CustomerService) { }

  ngOnInit() {
      this.customers$ = this.service.getCustomersByNationality('US');
  }
}

Implement CustomerUSComponent template file customer-us.component.html:

<div *ngFor="let cust of customers$ | async">
    <a [routerLink]="['/customers', cust.id]"><span class="badge badge-light badge-primary">{{cust.id}}</span> {{ cust.firstname }}</a>
</div>

Customer UK Component

– Implement CustomerUkComponent class in file customer-uk.component.ts:

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

import { Observable } from 'rxjs';

import { Customer } from '../customer'
import { CustomerService} from '../customer.service'

@Component({
  selector: 'app-customer-uk',
  templateUrl: './customer-uk.component.html',
  styleUrls: ['./customer-uk.component.css']
})
export class CustomerUkComponent implements OnInit {

  customers$: Observable;

  constructor(private service: CustomerService) { }

  ngOnInit() {
      this.customers$ = this.service.getCustomersByNationality('UK');
  }

}

– Implement CustomerUkComponent template file customer-uk.component.html :

<div *ngFor="let cust of customers$ | async">
    <a [routerLink]="['/customers', cust.id]"><span class="badge badge-light badge-primary">{{cust.id}}</span> {{ cust.firstname }}</a>
</div>

Customer Detail Component

– Implement CustomerDetailComponent class file customer-detail.component.ts :

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

import { switchMap } from 'rxjs/operators';
import { Router, ActivatedRoute, ParamMap } from '@angular/router';

import { Location } from '@angular/common';

import { Observable } from 'rxjs';

import { Customer } from '../customer';
import { CustomerService } from '../customer.service';

@Component({
  selector: 'app-customer-detail',
  templateUrl: './customer-detail.component.html',
  styleUrls: ['./customer-detail.component.css']
})
export class CustomerDetailComponent implements OnInit {

  customer$: Observable;

  constructor(  
    private route: ActivatedRoute,
    private location: Location,
    private service: CustomerService
  ) { }

  ngOnInit() {
    this.customer$ = this.route.paramMap.pipe(
      switchMap((params: ParamMap) =>
        this.service.getCustomer(params.get('id')))
    );
  }

  goBack(): void {
    this.location.back();
  }
}

Location is an Angular service for interacting with the browser. Depending on LocationStrategy, Location will either persist to the URL’s path or the URL’s hash segment.
ActivatedRoute contains the information about a route that can be used to traverse and retrieve the state of router tree.

We implement ngOnInit() to get info of a customer by service.getCustomer(params['id'])).
Using Location, a goBack() function navigates backward one step in the browser’s history stack.

– Implement CustomerDetailComponent template file customer-detail.component.html :

<div *ngIf="customer$ | async as customer">
  <h2><span class="badge badge-light ">{{customer.firstname}}</span></h2>
  <ul>
    <li>Id: {{customer.id}}</li>
    <li>Firstname: {{customer.firstname}}</li>
    <li>Lastname: {{customer.lastname}}</li>
    <li>Age: {{customer.age}}</li>
    <li>Nationality: {{customer.nationality}}</li>
  </ul>
</div>

<button type="button" class="btn btn-dark" (click)="goBack()">< Back</button>

PageNotFound Component

Implement PageNotFoundComponent template file page-not-found.component.html :

<div class="jumbotron text-center">
   <h1>404 Error!</h1>
   <p>PAGE NOT FOUND</p>
</div>

Source Code

How to run the below sourcecode:

1. Download Angular-6-Routing-Navigation.zip file -> Then extract it to Angular-6-Routing-Navigation folder.
2. Go to Angular-6-Routing-Navigation folder
3. Run the app by commandline: ng serve --open

-> Sourcecode:

Angular-6-Routing-Navigation

0 0 votes
Article Rating
Subscribe
Notify of
guest
2.5K Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments