페이지를 떠나기 전에 저장되지 않은 변경 사항에 대해 사용자에게 경고
사용자가 내 Angular 2 앱의 특정 페이지를 떠나기 전에 저장되지 않은 변경 사항에 대해 경고하고 싶습니다. 일반적으로을 사용 window.onbeforeunload
하지만 단일 페이지 응용 프로그램에서는 작동하지 않습니다.
앵귤러 1에서 $locationChangeStart
이벤트에 연결 confirm
하여 사용자를 위해 상자 를 던질 수 있지만 앵귤러 2에서이 작업을 수행하는 방법 또는 해당 이벤트가 여전히 존재하는지 여부를 보여주는 것은 본 적이 없습니다. . 에 대한 기능을 제공하는 ag1 용 플러그인 도 보았지만 onbeforeunload
다시 한 번, ag2에 대해 사용하는 방법을 보지 못했습니다.
다른 사람이이 문제에 대한 해결책을 찾았기를 바랍니다. 두 가지 방법 모두 내 목적에 적합합니다.
라우터는 수명주기 콜백 CanDeactivate를 제공합니다.
자세한 내용은 가드 튜토리얼을 참조하십시오.
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] }]) );
또한 브라우저 새로 고침, 창 닫기 등을 방지하기 위해 (문제에 대한 자세한 내용은 Günter의 답변에 대한 @ChristopheVidal의 의견 참조) 이벤트 를 수신하기 위해 @HostListener
클래스 canDeactivate
구현에 데코레이터를 추가하는 것이 도움이된다는 것을 알았습니다 beforeunload
window
. 올바르게 구성되면 인앱 및 외부 탐색을 동시에 차단합니다.
예를 들면 :
구성 요소:
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
}
}
가드:
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.');
}
}
노선 :
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] },
];
기준 치수:
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.
The example with the @Hostlistener from stewdebaker works really well, but I made one more change to it because IE and Edge display the "false" that is returned by the canDeactivate() method on the MyComponent class to the end user.
Component:
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)";
}
}
}
I've implemented the solution from @stewdebaker which works really well, however I wanted a nice bootstrap popup instead of the clunky standard JavaScript confirm. Assuming you're already using ngx-bootstrap, you can use @stwedebaker's solution, but swap the 'Guard' for the one I'm showing here. You also need to introduce ngx-bootstrap/modal
, and add a new ConfirmationComponent
:
Guard
(replace 'confirm' with a function that will open a bootstrap modal - displaying a new, custom ConfirmationComponent
):
import { Component, OnInit } from '@angular/core';
import { ConfirmationComponent } from './confirmation.component';
import { CanDeactivate } from '@angular/router';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { BsModalService } from 'ngx-bootstrap/modal';
import { BsModalRef } from 'ngx-bootstrap/modal';
export interface ComponentCanDeactivate {
canDeactivate: () => boolean | Observable<boolean>;
}
@Injectable()
export class PendingChangesGuard implements CanDeactivate<ComponentCanDeactivate> {
modalRef: BsModalRef;
constructor(private modalService: BsModalService) {};
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
this.openConfirmDialog();
}
openConfirmDialog() {
this.modalRef = this.modalService.show(ConfirmationComponent);
return this.modalRef.content.onClose.map(result => {
return result;
})
}
}
confirmation.component.html
<div class="alert-box">
<div class="modal-header">
<h4 class="modal-title">Unsaved changes</h4>
</div>
<div class="modal-body">
Navigate away and lose them?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" (click)="onConfirm()">Yes</button>
<button type="button" class="btn btn-secondary" (click)="onCancel()">No</button>
</div>
</div>
confirmation.component.ts
import { Component } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { BsModalRef } from 'ngx-bootstrap/modal';
@Component({
templateUrl: './confirmation.component.html'
})
export class ConfirmationComponent {
public onClose: Subject<boolean>;
constructor(private _bsModalRef: BsModalRef) {
}
public ngOnInit(): void {
this.onClose = new Subject();
}
public onConfirm(): void {
this.onClose.next(true);
this._bsModalRef.hide();
}
public onCancel(): void {
this.onClose.next(false);
this._bsModalRef.hide();
}
}
And since the new ConfirmationComponent
will be displayed without using a selector
in an html template, it needs to be declared in entryComponents
in your root app.module.ts
(or whatever you name your root module). Make the following changes to app.module.ts
:
app.module.ts
import { ModalModule } from 'ngx-bootstrap/modal';
import { ConfirmationComponent } from './confirmation.component';
@NgModule({
declarations: [
...
ConfirmationComponent
],
imports: [
...
ModalModule.forRoot()
],
entryComponents: [ConfirmationComponent]
The solution was easier than expected, don't use href
because this isn't handled by Angular Routing use routerLink
directive instead.
참고URL : https://stackoverflow.com/questions/35922071/warn-user-of-unsaved-changes-before-leaving-page
'program story' 카테고리의 다른 글
ASP.NET에서 SQL SERVER에 대한 연결 문자열 설정 (0) | 2020.08.31 |
---|---|
JavaScript를 사용하여 현재 URL에서 쿼리 문자열을 얻는 방법은 무엇입니까? (0) | 2020.08.31 |
자바 : Python의 범위 (int, int)와 동일합니까? (0) | 2020.08.31 |
HttpClient로 신뢰할 수없는 SSL 인증서 허용 (0) | 2020.08.31 |
src / lxml / etree_defs.h : 9 : 31 : 치명적인 오류 : libxml / xmlversion.h : 해당 파일 또는 디렉터리가 없습니다. (0) | 2020.08.31 |