Angular canDeactivate Guard Example

By Arvind Rai, February 28, 2024
This page will walk through Angular canDeactivate route guard example. The canDeactivate is a property of Route interface that is assigned with an array of CanDeactivateFn instances. CanDeactivateFn is a signature of function that performs as canDeactivate route guard. We can create an injectable service containing a method named as canDeactivate that will be injected 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. To shorten the code for creating canDeactivate guard, we can use Angular mapToCanDeactivate function.
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.

1. Technologies Used

Find the technologies being used in our example.
1. Angular 17.0.0
2. Node.js 20.10.0
3. NPM 10.2.3

2. CanDeactivateFn

CanDeactivateFn is a signature of function to create route guard that decides if a route can be deactivated. Find the signature of CanDeactivateFn from Angular doc.
type CanDeactivateFn<T> =
(
  component: T,
  currentRoute: ActivatedRouteSnapshot,
  currentState: RouterStateSnapshot,
  nextState: RouterStateSnapshot
) => Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree
} 
Parameters :
a. component : Component for which route is to be deactivated.
b. currentRoute : Instance of ActivatedRouteSnapshot for current route.
c. currentState : Instance of RouterStateSnapshot for current state.
d. nextState : Instance of RouterStateSnapshot for next state.

Returns :
CanDeactivateFn function will return Observable<boolean> or Promise<boolean> or boolean . If it returns true, route can be deactivated otherwise not.

3. Steps to Create canDeactivate Guard for any Component

To use canDeactivate guard in our application, create an injectable service and 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.
Angular canDeactivate Guard Example
Now we will discuss step-by-step to use canDeactivate in our application.

3.1 Create Service for CanDeactivate Guard

First we will create an interface that will declare canDeactivate method and using this interface we will create a service that will act as canDeactivate guard. This service will define canDeactivate method.
can-deactivate-guard.service.ts
export interface CanComponentDeactivate {
  canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean;
}

@Injectable()
export class CanDeactivateGuard {
  canDeactivate(component: CanComponentDeactivate, 
           route: ActivatedRouteSnapshot, 
           state: RouterStateSnapshot) {

     let url: string = state.url;
     console.log('Url: '+ url);

     return component.canDeactivate ? component.canDeactivate() : true;
  }
} 
The interface has declared 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. Our CanDeactivateGuard service can be used for any component.

3.2 Configure CanDeactivate Guard Service in Application Routing Module

We will configure our CanDeactivateGuard service 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);
  };
} 
We are passing an optional message for Dialog Box. The Boolean result will be returned as 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 created a service for canDeactivate 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;
	}	
} 
The method 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 route or navigate.

3.5 Add canDeactivate Guard to Component Route

We need to add our CanDeactivate 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: [
							(
								component: CanComponentDeactivate,
								currentRoute: ActivatedRouteSnapshot,
								currentState: RouterStateSnapshot,
								nextState: RouterStateSnapshot
							) => inject(CanDeactivateGuard).canDeactivate(component, currentRoute, currentState)
						]
					}
				]
			}
		]
	}
]; 
In this way, we can use CanDeactivate guard in our application for any component.

3.6 Using mapToCanDeactivate

mapToCanDeactivate maps an array of injectable classes containing method named as canDeactivate to an array of equivalent CanDeactivateFn. The mapToCanDeactivate is helpful to shorten the code writing to create canDeactivate route guard.
Let us use CanDeactivateGuard service with mapToCanDeactivate function.
path: '',
component: PersonListComponent,
children: [
	{
		path: ':id',
		component: PersonEditComponent,
		canDeactivate: mapToCanDeactivate([CanDeactivateGuard])
	}
] 
mapToCanDeactivate forces us to create a method named as canDeactivate in our injectable CanDeactivateGuard service otherwise code will not compile.

4. Component-Specific canDeactivate Guard

We can create component specific canDeactivate guard. Suppose we have a component CountryEditComponent and we want to create canDeactivate guard for this component.
country-edit-can-deactivate-guard.service.ts
@Injectable()
export class CountryEditCanDeactivateGuard {
  
  constructor(private dialogService: DialogService) { }

  canDeactivate(
    component: CountryEditComponent,
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean> | boolean {
    
      const 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;
  }
} 
Within 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 { } 
Now add guard to CountryEditComponent route in routing module using canDeactivate attribute.
path: 'list',
component: CountryListComponent,
children: [
	{
		path: 'edit/:country-id',
		component: CountryEditComponent,
		canDeactivate: mapToCanDeactivate([CountryEditCanDeactivateGuard])
	}
] 
In this way, we can use CanDeactivate guard in our application for a specific component.

5. Complete Example

can-deactivate-guard.service.ts
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';

export interface CanComponentDeactivate {
  canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean;
}

@Injectable()
export class CanDeactivateGuard {
  canDeactivate(
    component: CanComponentDeactivate,
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot) {

    const url: string = state.url;
    console.log('Url: ' + url);

    return component.canDeactivate ? component.canDeactivate() : true;
  }
} 
country-edit-can-deactivate-guard.service.ts
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { CountryEditComponent } from './country/country-list/edit/country.edit.component';
import { DialogService } from './dialog.service';

@Injectable()
export class CountryEditCanDeactivateGuard {

  constructor(private dialogService: DialogService) { }

  canDeactivate(
    component: CountryEditComponent,
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean> | boolean {

    const 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;
  }
} 
dialog.service.ts
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);
  };
} 
country.component.ts
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 { 
} 
country.ts
export class Country { 
	constructor(public countryId:number, public name:string,
            	public capital:string, public currency:string) {
	}
} 
country.module.ts
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 { } 
country-routing.module.ts
import { NgModule, inject } from '@angular/core';
import { ActivatedRouteSnapshot, RouterModule, RouterStateSnapshot, Routes, mapToCanDeactivate } 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 { CanComponentDeactivate, 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: [
					(
						component: CanComponentDeactivate,
						currentRoute: ActivatedRouteSnapshot,
						currentState: RouterStateSnapshot,
						nextState: RouterStateSnapshot
					) => inject(CanDeactivateGuard).canDeactivate(component, currentRoute, currentState)
				]
			},
			{
				path: 'list',
				component: CountryListComponent,
				children: [
					{
						path: 'edit/:country-id',
						component: CountryEditComponent,
						canDeactivate: mapToCanDeactivate([CountryEditCanDeactivateGuard])
					}
				]
			}
		]
	}
];

@NgModule({
	imports: [RouterModule.forChild(countryRoutes)],
	exports: [RouterModule]
})
export class CountryRoutingModule { } 
add-country.component.html
<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> 
add-country.component.ts
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;
		const name = this.countryForm.get('name')?.value ?? '';
		const capital = this.countryForm.get('capital')?.value ?? '';
		const currency = this.countryForm.get('currency')?.value ?? '';

		const 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;
	}
} 
country.list.component.html
<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> 
country.list.component.ts
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() {
  }
} 
country.edit.component.html
<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>  
country.edit.component.ts
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 })
			);
	}
} 
country.service.ts
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;
			}));
	}
} 
person.component.ts
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 { 
} 
person.ts
export class Person { 
	constructor(public personId:number, public name:string, public city:string) {
	}
} 
person-routing.module.ts
import { NgModule, inject } from '@angular/core';
import { ActivatedRouteSnapshot, CanDeactivateFn, RouterModule, RouterStateSnapshot, Routes, mapToCanDeactivate } 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: mapToCanDeactivate([CanDeactivateGuard])
					}
				]
			}
		]
	}
];

@NgModule({
	imports: [RouterModule.forChild(personRoutes)],
	exports: [RouterModule]
})
export class PersonRoutingModule { } 
person.module.ts
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 { } 
person.list.component.html
<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>  
person.list.component.ts
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 });
  }
} 
person.edit.component.html
<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> 
person.edit.component.ts
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;
	}
} 
person.service.ts
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;
      }));
  }
} 
page-not-found.component.ts
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();
        }
} 
app.component.ts
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 { 
} 
app-routing.module.ts
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 { }  
app.module.ts
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 { } 
styles.css
.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

Download source code using download link given below on this page and run the application.
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.
Angular canDeactivate Guard Example

7. References

8. Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI
LEARN MORE








©2024 concretepage.com | Privacy Policy | Contact Us