在离开页面之前警告未保存更改的用户
我想在离开我的angular2应用程序的特定页面之前提醒未保存更改的用户。 通常我会使用window.onbeforeunload
,但这不适用于单页面应用程序。
我已经发现,在angular1,你可以钩入$locationChangeStart
事件为用户抛出一个confirm
框,但我还没有看到任何东西显示如何得到这个工作angular2,或者如果该事件是甚至还存在。 我还看到了针对onbeforeunload
提供function的ag1 插件 ,但是我还没有看到用于ag2的任何方式。
我希望别人find了解决这个问题的办法。 任何方法都可以正常工作。
路由器提供了一个生命周期callback函数[CanDeactivate] https://angular.io/docs/ts/latest/api/router/index/CanDeactivate-interface.html ,您可以在其中阻止路由更改。
欲了解更多信息,请参阅守卫教程
class UserToken {} class Permissions { canActivate(user: UserToken, id: string): boolean { return true; } } @Injectable() class CanActivateTeam implements CanActivate { constructor(private permissions: Permissions, private currentUser: UserToken) {} canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Observable<boolean>|Promise<boolean>|boolean { return this.permissions.canActivate(this.currentUser, route.params.id); } } @NgModule({ imports: [ RouterModule.forRoot([ { path: 'team/:id', component: TeamCmp, canActivate: [CanActivateTeam] } ]) ], providers: [CanActivateTeam, UserToken, Permissions] }) class AppModule {}
原(RC.x路由器)
class CanActivateTeam implements CanActivate { constructor(private permissions: Permissions, private currentUser: UserToken) {} canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<boolean> { return this.permissions.canActivate(this.currentUser, this.route.params.id); } } bootstrap(AppComponent, [ CanActivateTeam, provideRouter([{ path: 'team/:id', component: Team, canActivate: [CanActivateTeam] }]) );
还包括防止浏览器刷新,closures窗口等(见@ ChristopheVidal对Günter的回答关于这个问题的详细评论),我发现将@HostListener
装饰器添加到你的类的canDeactivate
实现中是非常有用的,以侦听beforeunload
window
事件。 如果configuration正确,这将同时防范应用内和外部导航。
例如:
零件:
import {ComponentCanDeactivate} from './pending-changes.guard'; 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 } }
守卫:
import {CanDeactivate} from '@angular/router'; export interface ComponentCanDeactivate { canDeactivate: () => boolean | Observable<boolean>; } 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.'); } }
路线:
import {PendingChangesGuard} from './pending-changes.guard'; export const MY_ROUTES: Routes = [ { path: '', component: MyComponent, canDeactivate: [PendingChangesGuard] }, ];
模块:
import {PendingChangesGuard} from './pending-changes.guard'; @NgModule({ // ... providers: [PendingChangesGuard], // ... }) export class AppModule {}
注意 :正如@JasperRisseeuw指出的那样,IE和Edge处理beforeunload
事件的方式与其他浏览器不同,在beforeunload
事件激活时(例如,浏览器刷新,closures窗口等),将在确认对话框中包含单词false
。 在Angular应用程序内导航不受影响,并会正确显示您的指定确认警告消息。 那些需要支持IE / Edge并且不希望在beforeunload
事件激活时在确认对话框中显示/想要更详细的消息的人可能还想看@ JasperRisseeuw的解决方法。
来自stewdebaker的@Hostlistener的例子工作得很好,但我做了一个更改,因为IE和Edge显示了MyComponent类的canDeactivate()方法返回的“false”给最终用户。
零件:
import {ComponentCanDeactivate} from "./pending-changes.guard"; import { Observable } from 'rxjs'; // add this line export class MyComponent implements ComponentCanDeactivate { 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 alert before navigating away } // @HostListener allows us to also guard against browser refresh, close, etc. @HostListener('window:beforeunload', ['$event']) unloadNotification($event: any) { if (!this.canDeactivate()) { $event.returnValue = "This message is displayed to the user in IE and Edge when they navigate without using Angular routing (type another URL/close the browser/etc)"; } } }