In the code below (an example from the book "Angular 2 Development with TypeScript"):
import {CanDeactivate, Router} from "@angular/router";
import {Injectable} from "@angular/core";
@Injectable()
export class UnsavedChangesGuard implements CanDeactivate{
constructor(private _router:Router){}
canDeactivate(){
return window.confirm("You have unsaved changes. Still want to leave?");
}
}
I see a warning when I hover over CanDeactivate in WebStorm:
Referring to the answers to this question - Generic type 'Observable<T>' requires 1 type argument - the following change removes the warning:
export class UnsavedChangesGuard implements CanDeactivate<any>{
However, I would like to know how I can find out what is the actual argument that CanDeactivate requires.
Edit: Looking at @angular/router/src/interfaces.d.ts we can see the following:
/**
* @whatItDoes Indicates that a class can implement to be a guard deciding if a route can be
* deactivated.
*
* @howToUse
*
* ```
* class UserToken {}
* class Permissions {
* canDeactivate(user: UserToken, id: string): boolean {
* return true;
* }
* }
*
* @Injectable()
* class CanDeactivateTeam implements CanDeactivate<TeamComponent> {
* constructor(private permissions: Permissions, private currentUser: UserToken) {}
*
* canDeactivate(
* component: TeamComponent,
* route: ActivatedRouteSnapshot,
* state: RouterStateSnapshot
* ): Observable<boolean>|Promise<boolean>|boolean {
* return this.permissions.canDeactivate(this.currentUser, route.params.id);
* }
* }
*
* @NgModule({
* imports: [
* RouterModule.forRoot([
* {
* path: 'team/:id',
* component: TeamCmp,
* canDeactivate: [CanDeactivateTeam]
* }
* ])
* ],
* providers: [CanDeactivateTeam, UserToken, Permissions]
* })
* class AppModule {}
* ```
*
* You can also provide a function with the same signature instead of the class:
*
* ```
* @NgModule({
* imports: [
* RouterModule.forRoot([
* {
* path: 'team/:id',
* component: TeamCmp,
* canActivate: ['canDeactivateTeam']
* }
* ])
* ],
* providers: [
* {
* provide: 'canDeactivateTeam',
* useValue: (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => true
* }
* ]
* })
* class AppModule {}
* ```
*
* @stable
*/
export interface CanDeactivate<T> {
canDeactivate(component: T, route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean;
}
But it's not clear what "TeamComponent" is.
API documentation provides links to source code at the bottom of the page.
CanDeactivate
interface uses generics to type the first canDeactivate
argument (deactivated component):
export interface CanDeactivate<T> {
canDeactivate(
component: T, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot,
nextState?: RouterStateSnapshot): Observable<boolean>|Promise<boolean>|boolean;
}
As shown in this guide, canDeactivate
is called with deactivated component instance as an argument:
export interface CanComponentDeactivate {
canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean;
}
@Injectable()
export class CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate> {
canDeactivate(component: CanComponentDeactivate) {
return component.canDeactivate ? component.canDeactivate() : true;
}
}
Where component.canDeactivate
is just a method of the same name in component class, it doesn't necessarily have to be called canDeactivate
or even exist. And CanComponentDeactivate
is just user-defined interface that provides a convention for canDeactivate
component method.
This allows to interact with component during deactivation,
The canDeactivate() method provides you with the current instance of the component, the current ActivatedRoute, and RouterStateSnapshot in case you needed to access some external information. This would be useful if you only wanted to use this guard for this component and needed to get the component's properties or confirm whether the router should allow navigation away from it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With