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:
-> Navigation:
– Home Page (also US Customer Component page):
– UK Customer Component page:
– Details Customer page:
– Press go Back button:
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 Router
Angular project preparation
– Generate Angular project:
– Generate:
- 4 Components {
CustomerUsComponent
,CustomerUkComponent
,CustomerDetailComponent
,PageNotFoundComponent
} - Data Service:
CustomerService
- Module:
AppRoutingModule
- Class:
Customer
– 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: