angular - Generisk typ 'CanDeactivate<T>' kräver 1 typargument
I koden nedan (ett exempel från boken "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?");
}
}
Jag ser en varning när jag håller muspekaren över CanDeactivate i WebStorm:
Med hänvisning till svaren på denna fråga - Generisk typ 'Observable
export class UnsavedChangesGuard implements CanDeactivate<any>{
Men jag skulle vilja veta hur jag kan ta reda på vilket det faktiska argumentet är som CanDeactivate kräver.
Redigera: Genom att titta på @angular/router/src/interfaces.d.ts kan vi se följande:
/**
* @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;
}
Men det är inte klart vad "TeamComponent" är.
Svar #1
API-dokumentation tillhandahåller länkar till källkoden längst ner på sidan.
CanDeactivate-gränssnittet använder generics för att typa det första canDeactivate-argumentet (deaktiverad komponent):
export interface CanDeactivate<T> {
canDeactivate(
component: T, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot,
nextState?: RouterStateSnapshot): Observable<boolean>|Promise<boolean>|boolean;
}
Som visas i denna guide, kallas canDeactivate med den avaktiverade komponentinstansen som ett 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;
}
}
Där component.canDeactivate bara är en metod med samma namn i komponentklassen, behöver den inte nödvändigtvis kallas canDeactivate eller ens existera. Och CanComponentDeactivate är bara ett användardefinierat gränssnitt som tillhandahåller en konvention för canDeactivate-metoden i komponenten.
Detta möjliggör interaktion med komponenten under avaktiveringen,
Metoden canDeactivate() ger dig den aktuella instansen av komponenten, den aktuella ActivatedRoute och RouterStateSnapshot ifall du behövde få åtkomst till viss extern information. Detta skulle vara användbart om du bara ville använda denna guard för denna komponent och behövde få komponentens egenskaper eller bekräfta om routern borde tillåta navigering bort från den.
Svar #2
Jag hoppas att jag inte är för sen...
Baserat på ett svar från marco-barbero på en fråga: Finns det något sätt att förhindra att en komponent förstörs i Angular?
import { CanDeactivate } from '@angular/router';
import { CanDeactivateComponent } from './app/can-deactivate';
export class ConfirmDeactivateGuard implements CanDeactivate<any>
{
canDeactivate(target: any)
{
if(target.hasChanges()){
return window.confirm('Do you really want to cancel?');
}
return true;
}
}
Och i routerinmatningen för komponenten:
{
path: '',
component: SomeComponent,
canDeactivate: [ConfirmDeactivateGuard]
}
Slutligen, naturligtvis, inkludera vakten i en modul som en leverantör:
@NgModule({
...
providers: [
...
ConfirmDeactivateGuard
]
})
export class AppModule {
}
Observera användningen av any som en parameter för CanDeactivate()-metoden i en guard-klass. Anropet i rutten lägger till rätt parameter, så att du kan använda den i vilken komponent som helst. Det enda kravet är att implementera metoden hasChanges():boolean (med lämpligt villkor i varje) i varje komponent där du vill använda guarden.
