Conditional Guard with Angular
I use CanDeactivate in one of my projects to prevent the user from leaving a form that has unsaved changes which is indicated by its dirty state. Whenever there are still unsaved changes a confirmation message is displayed. Unfortunately the message was also displayed in inappropriate cases e.g. when the user is logged out because his session expired. To prevent this I did some research and came up with pretty simple solution.
dirty-check.guard.ts
import { Injectable } from '@angular/core';
import { of, Observable } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
import { DirtyComponent } from '../components/dirty.component';
import { MessageService } from '../services/message.service';
import { Router } from '@angular/router';
@Injectable({ providedIn: 'root' })
export class DirtyCheckGuard {
constructor(private readonly messageService: MessageService,
private readonly router: Router
) { }
canDeactivate(component: DirtyComponent): Observable<boolean> {
const ignoreDirtyCheck = this.router.getCurrentNavigation()?.extras?.state?.['ignoreDirtyCheck'] as boolean;
if(ignoreDirtyCheck) {
return of(true);
}
if (component?.isDirty) {
return component.isDirty
.unsubscribeOnDestroy(component)
.pipe(
mergeMap((value) => {
if (value) {
return this.messageService.openDirtyConfirm(component);
}
return of(true);
}));
}
else {
return of(true);
}
}
}
By using the NavigationExtras we can pass custom values into the router like this:
this.router.navigateByUrl('login', { state: { ignoreDirtyCheck: true } });
So whenever I want to navigate and "ignore" the guard, I just have to pass the custom flag inside the state object.