Angular 10 CanDeactivate
In this article, we'll learn about the CanDeactivate
route guard which a router guard is a browser event that's used to prompt or warn users that they're about to leave a page or in our case the Angular 10 app.
You can use the CanDeactivate guard to prevent usesr from accidentally leaving a route/page in your application for example if such page contains a text editor with unsaved changes or an unsubmitted form. You can let the user know they can't leave the component yet by using a confirmation or alert before the navigation to the other route takes place using the Angular CanDeactivate route guard.
Throughout this article, you'll see how to use the Angular CanDeactivate guard by example. CanDeactivate is a TypeScript interface that needs to be implemented by a component to create a route guard. This guard will be used by the router to decide if the route can be deactivated. It can be implemented in any Angular component using the canDeactivate
method of the interface.
Let's see how to implement CanDeactivate step by step with Angular 10.
The Angular CanDeactivate Interface
According to the docs:
Interface that a class can implement to be a guard deciding if a route can be deactivated. If all guards return true, navigation continues. If any guard returns false, navigation is cancelled. If any guard returns a UrlTree, current navigation is cancelled and a new navigation begins to the UrlTree returned from the guard.
This is the declaration of the interface:
interface CanDeactivate<T> {
canDeactivate(component: T, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState?: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree
}
The CanDeactivate
interface is a route guard that can be used by the router to decide if a route can deactivated.
The CanDeactivate interface provides a canDeactivate
method that takes the following arguments:
- The component that will be guarded.
ActivatedRouteSnapshot
RouterStateSnapshot
RouterStateSnapshot
The canDeactivate
method returns an Observable<boolean | UrlTree>
or Promise<boolean | UrlTree>
, UrlTree
, or boolean
.
Step 1 -- Creating the CanDeactivate Route Guard Service
Before implementing the CanDeactivate
route guard in our Angular 10 application, we'll need to create a guard as a service i.e a class decorated with the @Injectable()
decorator and should override the canDeactivate()
method.
Next, in our Angular component we also need to implement the canDeactivate()
method if we want to guard the component's route using CanDeactivate
.
Head back to your terminal, make sure you are inside your Angular 10 project's folder and run the following command to generate a new service:
$ ng generate service can-deactivate-guard
Next, you need to import the CanDeactivate
interface from the @angular/router
in your can-deactivate-guard
service.
Open the the src/app/can-deactivate-guard.service.ts
file and update it as follows:
import { Injectable } from '@angular/core';
import { CanDeactivate } from '@angular/router';
import { Observable } from 'rxjs/Observable';
export interface CanComponentDeactivate {
canDeactivate: () => Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree;
}
@Injectable()
export class CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate> {
canDeactivate(component: CanComponentDeactivate,
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot) {
return component.canDeactivate ? component.canDeactivate() : true;
}
}
We simply implement the CanDeactivate
interface with a generic component type that defines a canDeactivate
method. The CanDeactivate
interface contains one canDeactivate()
method that you need to override and pass the generic component as parameter so we can call the canDeactivate
method of of the component.
Step 2: Register The CanDeactivate Guard Service in the Application Routing Module
Next, we need to import our CanDeactivate guard service and add it the providers
array of the routing module.
Open the src/app/app-routing.module.ts
file and add CanDeactivateGuard
to the module as follows:
import { CanDeactivateGuard } from './can-deactivate-guard.service';
//[...]
@NgModule({
//[...]
providers: [
CanDeactivateGuard
]
})
export class AppRoutingModule { }
Step 3: Implement the canDeactivate()
Method in your Component
Next, we need to implement the canDeactivate()
method in our component, so first let's create the component.
Head back to your terminal and run the following command:
$ ng generate component product
Next, open the src/app/product/product.component.ts
file and update it as follows:
// [...]
import { Observable } from 'rxjs';
@Component({
templateUrl: './product.component.html'
})
export class ProductComponent implements OnInit {
unSaved: boolean = true;
constructor() { }
canDeactivate(): Observable<boolean> | boolean {
if (this.unSaved) {
const result = window.confirm('There are unsaved changes! Are you sure?');
return Observable.of(result);
}
return true;
}
}
The canDeactivate()
method of the component will be invoked by the CanDeactivateGuard
service to confirm if the user wants to navigate away when they are about to leave the component.
We simply added an unSaved
variable to indicate that we have some unsaved changes in our component that we need to save before leaving or otherwise the changes will be lost.
Step 4: Adding the CanDeactivate
Guard to the Route Configuration
Finally, we need to add our CanDeactivate
guard to the corresponding component's route in the routing module using the canDeactivate
property.
Open the src/app/app-routing.module.ts
file and import then add the CanDeactivateGuard
as follows:
const routes: Routes = [
{
path: 'product',
component: ProductComponent,
canDeactivate: [CanDeactivateGuard]
}
];
@NgModule({
imports: [ RouterModule.forChild(routes) ],
exports: [ RouterModule ]
})
export class AppRoutingModule{ }
Conclusion
We have created an Anguar 10 application that shows how to use the CanDeactivate
interface to create a route guard service for protecting a component from accidental user leaving.
-
Date: