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 @HostListener
decorador a la canDeactivate
implementación de su clase para escuchar el beforeunload
window
evento. 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 beforeunload
evento de manera diferente a otros navegadores e incluirán la palabra false
en el cuadro de diálogo de confirmación cuando el beforeunload
evento 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 false
mostrar / quieren un mensaje más detallado en el cuadro de diálogo de confirmación cuando beforeunload
se activa el evento, también pueden querer ver la respuesta de @ JasperRisseeuw para una solución alternativa.