To also cover guards against browser refreshes, closing the window, etc. (see @ChristopheVidal's comment to Günter's answer for details on the issue), I have found it helpful to add the @HostListener
decorator to your class's canDeactivate
implementation to listen for the beforeunload
window
event. When configured correctly, this will guard against both in-app and external navigation at the same time.
For example:
Component:
import { ComponentCanDeactivate } from './pending-changes.guard';
import { HostListener } from '@angular/core';
import { Observable } from 'rxjs/Observable';
export class MyComponent implements ComponentCanDeactivate {
@HostListener('window:beforeunload')
canDeactivate(): Observable<boolean> | boolean {
}
}
Guard:
import { CanDeactivate } from '@angular/router';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
export interface ComponentCanDeactivate {
canDeactivate: () => boolean | Observable<boolean>;
}
@Injectable()
export class PendingChangesGuard implements CanDeactivate<ComponentCanDeactivate> {
canDeactivate(component: ComponentCanDeactivate): boolean | Observable<boolean> {
return component.canDeactivate() ?
true :
confirm('WARNING: You have unsaved changes. Press Cancel to go back and save these changes, or OK to lose these changes.');
}
}
Routes:
import { PendingChangesGuard } from './pending-changes.guard';
import { MyComponent } from './my.component';
import { Routes } from '@angular/router';
export const MY_ROUTES: Routes = [
{ path: '', component: MyComponent, canDeactivate: [PendingChangesGuard] },
];
Module:
import { PendingChangesGuard } from './pending-changes.guard';
import { NgModule } from '@angular/core';
@NgModule({
providers: [PendingChangesGuard],
})
export class AppModule {}
NOTE: As @JasperRisseeuw pointed out, IE and Edge handle the beforeunload
event differently from other browsers and will include the word false
in the confirm dialog when the beforeunload
event activates (e.g., browser refreshes, closing the window, etc.). Navigating away within the Angular app is unaffected and will properly show your designated confirmation warning message. Those who need to support IE/Edge and don't want false
to show/want a more detailed message in the confirm dialog when the beforeunload
event activates may also want to see @JasperRisseeuw's answer for a workaround.