Angular CanDeactivate Guard Example
August 29, 2021
This page will walk through Angular CanDeactivate
guard example. The CanDeactivate
is an interface that is implemented by our class to create a route guard to decide if a route can be deactivated. The guard can be added to any component route using canDeactivate
attribute of Angular Route
interface. Any route which needs to use CanDeactivate
guard, has to define canDeactivate
method and that will be called by our route guard service. We can also create component-specific CanDeactivate
guard. The route guard is created as Angular service and Router
can inject it during the navigation process. While deactivating route using CanDeactivate
guard, we need to open a confirmation dialog box to take user confirmation if user wants to stay on the page or leave the page.
The
CanDeactivate
guard can be used in the scenario where a user is changing form data and before saving, user tries to navigate away. In this scenario we can use CanDeactivate
guard to deactivate the route and open a Dialog Box to take user confirmation.
Here on this page we will create
CanDeactivate
guard that can be used with any component and we will also create component specific CanDeactivate
guard. Now let us discuss complete example step-by-step.
Contents
Technologies Used
Find the technologies being used in our example.1. Angular 12.1.0
2. Node.js 12.14.1
3. NPM 7.20.3
2. CanDeactivate Interface
CanDeactivate
interface is a route guard to decide if a route can deactivated. Find the structure of CanDeactivate
interface from Angular doc.
interface CanDeactivate<T> { canDeactivate(component: T, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState?: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean }
CanDeactivate
interface has a method canDeactivate
that accepts arguments as given below.
a. Component for which route is to be deactivated.
b.
ActivatedRouteSnapshot
c.
RouterStateSnapshot
d.
RouterStateSnapshot
canDeactivate
method will return Observable<boolean>
or Promise<boolean>
or boolean
.
3. Steps to Create CanDeactivate Guard for any Component
To useCanDeactivate
in our application, we need to create a guard. This will be a service decorated with @Injectable()
and will define canDeactivate()
method. If a component needs CanDeactivate
route guard then that component has also to create a method named as canDeactivate()
.
Find the sample output of our application for
CanDeactivate
guard.

CanDeactivate
in our application.
3.1 Create Service for CanDeactivate Guard
First we will create an interface that will declarecanDeactivate
method and using this interface we will create a service that will act as CanDeactivate
guard. This service will define canDeactivate
method. Now find our CanDeactivate
guard.
can-deactivate-guard.service.ts
export interface CanComponentDeactivate { canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean; } @Injectable() export class CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate> { canDeactivate(component: CanComponentDeactivate, route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { let url: string = state.url; console.log('Url: '+ url); return component.canDeactivate ? component.canDeactivate() : true; } }
canDeactivate
method whose return type is Observable<boolean>
or Promise<boolean>
or boolean
. In the service code, we need to call canDeactivate
method using component instance. For any component which has defined canDeactivate
method, that method will be called by component instnace otherwise true will be returned by the above guard. We can access current route and current state, too. In this way we have created our CanDeactivate
guard .i.e. CanDeactivateGuard
service in our example that can be used for any component.
3.2 Configure CanDeactivate Guard Service in Application Routing Module
We will configure ourCanDeactivate
guard service i.e. CanDeactivateGuard
in application routing module using providers
attribute of @NgModule
decorator. We need to add it in main application routing module so that Router
can inject it during the navigation process.
import { CanDeactivateGuard } from './can-deactivate-guard.service'; ------ @NgModule({ ------ providers: [ CanDeactivateGuard ] }) export class AppRoutingModule { }
3.3 Create Service for Confirmation Dialog Box
Create a service for Confirmation Dialog Box.dialog.service.ts
@Injectable() export class DialogService { confirm(message?: string): Observable<boolean> { const confirmation = window.confirm(message || 'Are you sure?'); return Observable.of(confirmation); }; }
Observable
. We need to configure the above service in application module using providers
attribute of @NgModule
decorator.
3.4 Create canDeactivate() method within Component
We have createdCanDeactivate
guard .i.e. CanDeactivateGuard
and it can be used for any component. Suppose we have a component as PersonEditComponent
that will perform update operation for person details. If we want to use CanDeactivate
guard for this component then we need to create canDeactivate()
method within this component.
@Component({ templateUrl: './person.edit.component.html' }) export class PersonEditComponent implements OnInit { ------ constructor( public dialogService: DialogService) { } canDeactivate(): Observable<boolean> | boolean { if (!this.isUpdating && this.personForm.dirty) { return this.dialogService.confirm('Discard changes for Person?'); } return true; } }
canDeactivate()
of this component will be called by CanDeactivateGuard
service. The canDeactivate()
method of the above component will open a Dialog Box to ask if we want to stay on the page or leave the page.
3.5 Add CanDeactivate Guard to Component Route in Routing Module
We need to add ourCanDeactivate
guard .i.e. CanDeactivateGuard
to component route in routing module using canDeactivate
attribute.
const personRoutes: Routes = [ { path: 'person', component: PersonComponent, children: [ { path: '', component: PersonListComponent, children: [ { path: ':id', component: PersonEditComponent, canDeactivate: [CanDeactivateGuard] } ] } ] } ]; @NgModule({ imports: [ RouterModule.forChild(personRoutes) ], exports: [ RouterModule ] }) export class PersonRoutingModule{ }
CanDeactivate
guard in our application for any component.
4. Component-Specific CanDeactivate Guard
We can create component specificCanDeactivate
guard. Suppose we have a component CountryEditComponent
and we want to create CanDeactivate
guard for this component. The guard needs to implement Angular CanDeactivate
interface and will define canDeactivate()
method. Find the code as following.
country-edit-can-deactivate-guard.service.ts
@Injectable() export class CountryEditCanDeactivateGuard implements CanDeactivate<CountryEditComponent> { constructor(private dialogService: DialogService) { } canDeactivate( component: CountryEditComponent, route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Observable<boolean> | boolean { let url: string = state.url; console.log('Url: '+ url); if (!component.isUpdating && component.countryForm.dirty) { component.isUpdating = false; return this.dialogService.confirm('Discard changes for Country?'); } return true; } }
canDeactivate()
method we need to open our Confirmation Dialog Box.
We will configure
CountryEditCanDeactivateGuard
in main application routing module so that Router
can inject it during the navigation process.
import { CanDeactivateGuard } from './can-deactivate-guard.service'; import { CountryEditCanDeactivateGuard } from './country-edit-can-deactivate-guard.service'; ------ @NgModule({ ------ providers: [ CanDeactivateGuard, CountryEditCanDeactivateGuard ] }) export class AppRoutingModule { }
CountryEditComponent
route in routing module using canDeactivate
attribute.
const countryRoutes: Routes = [ { path: 'country', component: CountryComponent, children: [ { path: 'add', component: AddCountryComponent, canDeactivate: [CanDeactivateGuard] }, { path: 'list', component: CountryListComponent, children: [ { path: 'edit/:country-id', component: CountryEditComponent, canDeactivate: [CountryEditCanDeactivateGuard] } ] } ] } ]; @NgModule({ imports: [ RouterModule.forChild(countryRoutes) ], exports: [ RouterModule ] }) export class CountryRoutingModule { }
CanDeactivate
guard in our application for a specific component.
5. Complete Example
Find the project structure of our application.angular-demo | |--src | | | |--app | | | | | |--can-deactivate-guard.service.ts | | |--country-edit-can-deactivate-guard.service.ts | | |--dialog.service.ts | | | | | |--country | | | | | | | |--country.component.ts | | | |--country.ts | | | |--country.module.ts | | | |--country-routing.module.ts | | | | | | | |--add-country | | | | | | | | | |--add-country.component.html | | | | |--add-country.component.ts | | | | | | | |--country-list | | | | | | | | | |--country.list.component.html | | | | |--country.list.component.ts | | | | | | | | | |--edit | | | | | | | | | | | |--country.edit.component.html | | | | | |--country.edit.component.ts | | | | | | | | | | | | |--services | | | | | | | | | |--country.service.ts | | | | | | | | | |--person | | | | | | | |--person.component.ts | | | |--person.ts | | | |--person-routing.module.ts | | | |--person.module.ts | | | | | | | |--person-list | | | | | | | | | |--person.list.component.html | | | | |--person.list.component.ts | | | | | | | | | |--edit | | | | | | | | | | | |--person.edit.component.html | | | | | |--person.edit.component.ts | | | | | | | |--services | | | | | | | | | |--person.service.ts | | | | | | | | | |--page-not-found.component.ts | | |--app.component.ts | | |--app-routing.module.ts | | |--app.module.ts | | | |--main.ts | |--index.html | |--styles.css | |--node_modules |--package.json
can-deactivate-guard.service.ts
import { Injectable } from '@angular/core'; import { CanDeactivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { Observable } from 'rxjs'; export interface CanComponentDeactivate { canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean; } @Injectable() export class CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate> { canDeactivate(component: CanComponentDeactivate, route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { let url: string = state.url; console.log('Url: ' + url); return component.canDeactivate ? component.canDeactivate() : true; } }
import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { CanDeactivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { CountryEditComponent } from './country/country-list/edit/country.edit.component'; import { DialogService } from './dialog.service'; @Injectable() export class CountryEditCanDeactivateGuard implements CanDeactivate<CountryEditComponent> { constructor(private dialogService: DialogService) { } canDeactivate( component: CountryEditComponent, route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Observable<boolean> | boolean { let url: string = state.url; console.log('Url: ' + url); if (!component.isUpdating && component.countryForm.dirty) { component.isUpdating = false; return this.dialogService.confirm('Discard changes for Country?'); } return true; } }
import { Injectable } from '@angular/core'; import { Observable, of } from 'rxjs'; @Injectable() export class DialogService { confirm(message?: string): Observable<boolean> { const confirmation = window.confirm(message || 'Are you sure?'); return of(confirmation); }; }
import { Component } from '@angular/core'; @Component({ template: `<h2>Welcome to Country Home</h2> <nav [ngClass] = "'child-menu'"> <ul> <li><a [routerLink]="['add']" routerLinkActive="active">Add Country</a></li> <li><a [routerLink]="['list']" routerLinkActive="active">Country List</a></li> </ul> </nav> <div [ngClass] = "'child-container'"> <router-outlet></router-outlet> </div> ` }) export class CountryComponent { }
export class Country { constructor(public countryId:number, public name:string, public capital:string, public currency:string) { } }
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ReactiveFormsModule } from '@angular/forms'; import { CountryComponent } from './country.component'; import { AddCountryComponent } from './add-country/add-country.component'; import { CountryListComponent } from './country-list/country.list.component'; import { CountryEditComponent } from './country-list/edit/country.edit.component'; import { CountryService } from './services/country.service'; import { CountryRoutingModule } from './country-routing.module'; @NgModule({ imports: [ CommonModule, ReactiveFormsModule, CountryRoutingModule ], declarations: [ CountryComponent, AddCountryComponent, CountryListComponent, CountryEditComponent ], providers: [ CountryService ] }) export class CountryModule { }
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { CountryComponent } from './country.component'; import { CountryListComponent } from './country-list/country.list.component'; import { AddCountryComponent } from './add-country/add-country.component'; import { CountryEditComponent } from './country-list/edit/country.edit.component'; import { CanDeactivateGuard } from '../can-deactivate-guard.service'; import { CountryEditCanDeactivateGuard } from '../country-edit-can-deactivate-guard.service'; const countryRoutes: Routes = [ { path: 'country', component: CountryComponent, children: [ { path: 'add', component: AddCountryComponent, canDeactivate: [CanDeactivateGuard] }, { path: 'list', component: CountryListComponent, children: [ { path: 'edit/:country-id', component: CountryEditComponent, canDeactivate: [CountryEditCanDeactivateGuard] } ] } ] } ]; @NgModule({ imports: [ RouterModule.forChild(countryRoutes) ], exports: [ RouterModule ] }) export class CountryRoutingModule { }
<h3>Add Country</h3> <form [formGroup]="countryForm" (ngSubmit)="onFormSubmit()"> <p> Name: <input formControlName="name"> </p> <p> Capital: <input formControlName="capital"> </p> <p> Currency: <input formControlName="currency"> </p> <p> <button>Add</button> </p> </form>
import { Component } from '@angular/core'; import { FormBuilder } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { CountryService } from '../services/country.service'; import { Country } from '../country'; import { DialogService } from '../../dialog.service'; import { Observable } from 'rxjs'; @Component({ templateUrl: './add-country.component.html' }) export class AddCountryComponent { isAdding = false; constructor( private countryService: CountryService, private route: ActivatedRoute, private router: Router, private formBuilder: FormBuilder, private dialogService: DialogService) { } countryForm = this.formBuilder.group({ name: '', capital: '', currency: '' }); onFormSubmit() { this.isAdding = true; let name = this.countryForm.get('name')?.value; let capital = this.countryForm.get('capital')?.value; let currency = this.countryForm.get('currency')?.value; let country = new Country(0, name, capital, currency); this.countryService.addCountry(country) .subscribe(() => this.router.navigate(['../list'], { relativeTo: this.route }) ); } canDeactivate(): Observable<boolean> | boolean { if (!this.isAdding && this.countryForm.dirty) { return this.dialogService.confirm('Discard unsaved Country?'); } return true; } }
<h3>Country List</h3> <div *ngFor="let country of countries | async" [ngClass]= "'sub-child-menu'"> <p> {{country.countryId}} - {{country.name}} - {{country.capital}} - {{country.currency}} | <a [routerLink]="['edit', country.countryId]" routerLinkActive="active">Edit</a> </p> </div> <div [ngClass]= "'sub-child-container'"> <router-outlet></router-outlet> </div>
import { Component, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; import { CountryService } from '../services/country.service'; import { Country } from '../country'; @Component({ templateUrl: './country.list.component.html' }) export class CountryListComponent implements OnInit { countries: Observable<Country[]>; constructor(private countryService: CountryService) { this.countries = this.countryService.getCountries(); } ngOnInit() { } }
<h3>Edit Country</h3> <p *ngIf="country"><b>Country Id: {{country.countryId }} </b></p> <form [formGroup]="countryForm" (ngSubmit)="onFormSubmit()"> <p> Name: <input formControlName="name"> </p> <p> Capital: <input formControlName="capital"> </p> <p> Currency: <input formControlName="currency"> </p> <p> <button>Update</button> </p> </form>
import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router, Params } from '@angular/router'; import { FormGroup, FormBuilder } from '@angular/forms'; import { switchMap } from 'rxjs/operators'; import { CountryService } from '../../services/country.service'; import { Country } from '../../country'; @Component({ templateUrl: './country.edit.component.html' }) export class CountryEditComponent implements OnInit { country = {} as Country; countryForm = {} as FormGroup; isUpdating = false; constructor( private countryService: CountryService, private route: ActivatedRoute, private router: Router, private formBuilder: FormBuilder) { } ngOnInit() { this.route.params.pipe( switchMap((params: Params) => this.countryService.getCountry(+params['country-id'])) ).subscribe(country => { this.country = country ?? {} as Country; this.createForm(country); }); } createForm(country: Country | undefined) { this.countryForm = this.formBuilder.group({ name: country?.name, capital: country?.capital, currency: country?.currency }); } onFormSubmit() { this.isUpdating = true; this.country.name = this.countryForm.get('name')?.value; this.country.capital = this.countryForm.get('capital')?.value; this.country.currency = this.countryForm.get('currency')?.value; this.countryService.updateCountry(this.country) .subscribe(() => this.router.navigate(['../../'], { relativeTo: this.route }) ); } }
import { Injectable } from '@angular/core'; import { Observable, of } from 'rxjs'; import { map } from 'rxjs/operators'; import { Country } from '../country'; const COUNTRIES = [ new Country(1, 'India', 'New Delhi', 'INR'), new Country(2, 'China', 'Beijing', 'RMB') ]; let countriesObservable = of(COUNTRIES); @Injectable() export class CountryService { getCountries() { return countriesObservable; } getCountry(id: number) { return this.getCountries().pipe( map(countries => countries.find(country => country.countryId === id)) ); } updateCountry(country: Country) { return this.getCountries().pipe( map(countries => { let countryObj = countries.find(ob => ob.countryId === country.countryId); countryObj = country; return countryObj; })); } addCountry(country: Country) { return this.getCountries().pipe( map(countries => { let maxIndex = countries.length - 1; let countryWithMaxIndex = countries[maxIndex]; country.countryId = countryWithMaxIndex.countryId + 1; countries.push(country); return country; })); } }
import { Component } from '@angular/core'; @Component({ template: ` <h2>Welcome to Person Home</h2> <div [ngClass] = "'child-container'"> <router-outlet></router-outlet> </div> ` }) export class PersonComponent { }
export class Person { constructor(public personId:number, public name:string, public city:string) { } }
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { PersonComponent } from './person.component'; import { PersonListComponent } from './person-list/person.list.component'; import { PersonEditComponent } from './person-list/edit/person.edit.component'; import { CanDeactivateGuard } from '../can-deactivate-guard.service'; const personRoutes: Routes = [ { path: 'person', component: PersonComponent, children: [ { path: '', component: PersonListComponent, children: [ { path: ':id', component: PersonEditComponent, canDeactivate: [CanDeactivateGuard] } ] } ] } ]; @NgModule({ imports: [ RouterModule.forChild(personRoutes) ], exports: [ RouterModule ] }) export class PersonRoutingModule{ }
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ReactiveFormsModule } from '@angular/forms'; import { PersonComponent } from './person.component'; import { PersonListComponent } from './person-list/person.list.component'; import { PersonEditComponent } from './person-list/edit/person.edit.component'; import { PersonService } from './services/person.service'; import { PersonRoutingModule } from './person-routing.module'; @NgModule({ imports: [ CommonModule, ReactiveFormsModule, PersonRoutingModule ], declarations: [ PersonComponent, PersonListComponent, PersonEditComponent ], providers: [ PersonService ] }) export class PersonModule { }
<h3>Person List</h3> <div *ngFor="let person of persons | async" [ngClass]= "'sub-child-menu'"> <p>{{person.personId}}. {{person.name}}, {{person.city}} <button type="button" (click)="goToEdit(person)">Edit</button> </p> </div> <div [ngClass]= "'sub-child-container'"> <router-outlet></router-outlet> </div>
import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { Observable } from 'rxjs'; import { PersonService } from '../services/person.service'; import { Person } from '../person'; @Component({ templateUrl: './person.list.component.html' }) export class PersonListComponent implements OnInit { persons: Observable<Person[]>; constructor( private personService: PersonService, private route: ActivatedRoute, private router: Router) { this.persons = this.personService.getPersons(); } ngOnInit() { } goToEdit(person: Person) { this.router.navigate([person.personId], { relativeTo: this.route }); } }
<h3>Edit Person</h3> <p *ngIf="person"><b>Person Id: {{person.personId }} </b></p> <form [formGroup]="personForm" (ngSubmit)="onFormSubmit()"> <p> Name: <input formControlName="name"> </p> <p> City: <input formControlName="city"> </p> <p> <button>Update</button> </p> </form>
import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router, Params } from '@angular/router'; import { FormGroup, FormBuilder } from '@angular/forms'; import { Observable } from 'rxjs'; import { switchMap } from 'rxjs/operators'; import { PersonService } from '../../services/person.service'; import { Person } from '../../person'; import { DialogService } from '../../../dialog.service'; @Component({ templateUrl: './person.edit.component.html' }) export class PersonEditComponent implements OnInit { person = {} as Person; personForm = {} as FormGroup; isUpdating = false; constructor( private personService: PersonService, private route: ActivatedRoute, private router: Router, private formBuilder: FormBuilder, private dialogService: DialogService) { } ngOnInit() { this.route.params.pipe( switchMap((params: Params) => this.personService.getPerson(+params['id'])) ).subscribe(person => { this.person = person ?? {} as Person; this.createForm(person); }); } createForm(person: Person | undefined) { this.personForm = this.formBuilder.group({ name: person?.name, city: person?.city }); } onFormSubmit() { this.isUpdating = true; this.person.name = this.personForm.get('name')?.value; this.person.city = this.personForm.get('city')?.value; this.personService.updatePerson(this.person) .subscribe(() => this.router.navigate(['../'], { relativeTo: this.route }) ); } canDeactivate(): Observable<boolean> | boolean { if (!this.isUpdating && this.personForm.dirty) { this.isUpdating = false; return this.dialogService.confirm('Discard changes for Person?'); } return true; } }
import { Injectable } from '@angular/core'; import { Observable, of } from 'rxjs'; import { map } from 'rxjs/operators'; import { Person } from '../person'; const PERSONS = [ new Person(1, 'Mahesh', 'Varanasi'), new Person(2, 'Ram', 'Ayodhya'), new Person(3, 'Krishn', 'Mathura') ]; let personsObservable = of(PERSONS); @Injectable() export class PersonService { getPersons(): Observable<Person[]> { return personsObservable; } getPerson(id: number) { return this.getPersons().pipe( map(persons => persons.find(person => person.personId === id)) ); } updatePerson(person: Person) { return this.getPersons().pipe( map(persons => { let personObj = persons.find(ob => ob.personId === person.personId); personObj = person; return personObj; })); } }
import { Component } from '@angular/core'; import { Location } from '@angular/common'; @Component({ template: `<h2>Page Not Found.</h2> <div> <button (click)="goBack()">Go Back</button> </div> ` }) export class PageNotFoundComponent { constructor(private location: Location) { } goBack(): void { this.location.back(); } }
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` <nav [ngClass] = "'parent-menu'"> <ul> <li><a routerLink="/country" routerLinkActive="active">Country</a></li> <li><a routerLink="/person" routerLinkActive="active">Person</a></li> </ul> </nav> <router-outlet></router-outlet> ` }) export class AppComponent { }
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { PageNotFoundComponent } from './page-not-found.component'; import { CanDeactivateGuard } from './can-deactivate-guard.service'; import { CountryEditCanDeactivateGuard } from './country-edit-can-deactivate-guard.service'; const routes: Routes = [ { path: '', redirectTo: '/country', pathMatch: 'full' }, { path: '**', component: PageNotFoundComponent } ]; @NgModule({ imports: [ RouterModule.forRoot(routes) ], exports: [ RouterModule ], providers: [ CanDeactivateGuard, CountryEditCanDeactivateGuard, ], }) export class AppRoutingModule { }
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; import { PageNotFoundComponent } from './page-not-found.component'; import { CountryModule } from './country/country.module'; import { PersonModule } from './person/person.module'; import { AppRoutingModule } from './app-routing.module'; import { DialogService } from './dialog.service'; @NgModule({ imports: [ BrowserModule, CountryModule, PersonModule, AppRoutingModule, ], declarations: [ AppComponent, PageNotFoundComponent ], providers: [ DialogService ], bootstrap: [ AppComponent ] }) export class AppModule { }
.parent-menu ul { list-style-type: none; margin: 0; padding: 0; overflow: hidden; background-color: #333; } .parent-menu li { float: left; } .parent-menu li a { display: block; color: white; text-align: center; padding: 15px 15px; text-decoration: none; } .parent-menu li a:hover:not(.active) { background-color: #111; } .parent-menu .active{ background-color: #4CAF50; } .child-container { padding-left: 10px; } .sub-child-container { padding-left: 10px; } .child-menu { padding-left: 25px; } .child-menu .active{ color: #4CAF50; } .sub-child-menu { background-color: #f1f1f1; width: 275px; list-style-type: none; margin: 0; padding: 0; } .sub-child-menu .active{ color: #4CAF50; } button { background-color: #008CBA; color: white; }
6. Run Application
To run the application, find following steps.1. Download source code using download link given below on this page.
2. Use downloaded src in your Angular CLI application. To install Angular CLI, find the link.
3. Run ng serve using command prompt.
4. Now access the URL http://localhost:4200
Click on the country and go to add country. Fill data and try to navigate away. We will get Confirmation Dialog Box to ask if we want to discard unsaved data.

7. References
Angular Doc: CanDeactivateCommon Routing Tasks
Angular Child Routes and Relative Navigation Example