Para cubrir también las protecciones contra las actualizaciones del navegador, el cierre de la ventana, etc. (consulte el comentario de @ChristopheVidal a la respuesta de Günter para obtener detalles sobre el problema), me ha resultado útil agregar el @HostListenerdecorador a la canDeactivateimplementación de su clase para escuchar el beforeunload windowevento. Cuando se configura correctamente, esto protegerá contra la navegación externa y dentro de la aplicación al mismo tiempo.
Por ejemplo:
Componente:
import { ComponentCanDeactivate } from './pending-changes.guard';
import { HostListener } from '@angular/core';
import { Observable } from 'rxjs/Observable';
export class MyComponent implements ComponentCanDeactivate {
// @HostListener allows us to also guard against browser refresh, close, etc.
@HostListener('window:beforeunload')
canDeactivate(): Observable<boolean> | boolean {
// insert logic to check if there are pending changes here;
// returning true will navigate without confirmation
// returning false will show a confirm dialog before navigating away
}
}
Guardia:
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> {
// if there are no pending changes, just allow deactivation; else confirm first
return component.canDeactivate() ?
true :
// NOTE: this warning message will only be shown when navigating elsewhere within your angular app;
// when navigating away from your angular app, the browser will show a generic warning message
// see http://stackoverflow.com/a/42207299/7307355
confirm('WARNING: You have unsaved changes. Press Cancel to go back and save these changes, or OK to lose these changes.');
}
}
Rutas:
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] },
];
Módulo:
import { PendingChangesGuard } from './pending-changes.guard';
import { NgModule } from '@angular/core';
@NgModule({
// ...
providers: [PendingChangesGuard],
// ...
})
export class AppModule {}
NOTA : Como señaló @JasperRisseeuw, IE y Edge manejan el beforeunloadevento de manera diferente a otros navegadores e incluirán la palabra falseen el cuadro de diálogo de confirmación cuando el beforeunloadevento se active (por ejemplo, el navegador se actualiza, cierra la ventana, etc.). La navegación dentro de la aplicación Angular no se ve afectada y mostrará correctamente el mensaje de advertencia de confirmación designado. Aquellos que necesitan ser compatibles con IE / Edge y no quieren falsemostrar / quieren un mensaje más detallado en el cuadro de diálogo de confirmación cuando beforeunloadse activa el evento, también pueden querer ver la respuesta de @ JasperRisseeuw para una solución alternativa.