페이지를 나가기 전에 저장하지 않은 변경 사항에 대해 사용자에게 경고
저는 사용자들이 제 각진 2 앱의 특정 페이지를 떠나기 전에 저장되지 않은 변경 사항에 대해 경고하고 싶습니다.일반적으로 사용합니다.window.onbeforeunload그러나 단일 페이지 응용 프로그램에서는 작동하지 않습니다.
각도 1에서, 당신은 그것에 걸 수 있습니다.$locationChangeStart토하기 위한 이벤트confirm사용자를 위한 상자이지만 각도 2에 대해 이 작업을 수행하는 방법이나 해당 이벤트가 아직 있는지 여부를 보여주는 것을 본 적이 없습니다.또한 AG1용 플러그인을 통해onbeforeunload하지만 다시 말하지만, 나는 그것을 ag2에 사용할 방법을 찾지 못했습니다.
저는 다른 사람이 이 문제에 대한 해결책을 찾았기를 바랍니다. 어느 방법이든 제 목적에 잘 맞을 것입니다.
또한 브라우저 새로 고침, 창 닫기 등에 대한 가드를 커버하기 위해(이 문제에 대한 자세한 내용은 귄터의 답변에 대한 @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 {}
참고: @Jasper Risseow가 지적했듯이 IE와 Edge는 다음을 처리합니다.beforeunload다른 브라우저와 다르게 이벤트를 수행하고 단어를 포함할 것입니다.false확인 대화 상자에서 다음과 같은 경우beforeunload이벤트가 활성화됩니다(예: 브라우저 새로 고침, 창 닫기 등).Angular 앱 내에서 탐색해도 영향을 받지 않으며 지정된 확인 경고 메시지가 올바르게 표시됩니다.IE/Edge를 지원해야 하지만 지원하지 않는 고객false확인 대화 상자에 더 자세한 메시지를 표시하거나 표시합니다.beforeunload이벤트 활성화는 또한 해결 방법에 대한 @Jasper Risseow의 답변을 보고 싶어할 수도 있습니다.
라우터는 수명 주기 콜백을 제공합니다. CanDisactivate
자세한 내용은 가드 튜토리얼 참조
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] }]) );
stoodebaker의 @Hostlistener를 사용한 예제는 매우 잘 작동하지만 IE와 Edge가 MyComponent 클래스의 canDeconate() 메서드에서 반환되는 "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)";
}
}
}
저는 @stewdebaker의 솔루션을 구현했는데, 매우 잘 작동합니다. 하지만 저는 투박한 표준 자바스크립트 확인 대신 멋진 부트스트랩 팝업을 원했습니다.이미 ngx-bootstrap을 사용하고 있다고 가정하면 @stwedebaker의 솔루션을 사용할 수 있지만, 'Guard'를 제가 여기서 보여드리는 솔루션과 바꿀 수 있습니다.당신은 또한 소개할 필요합니다.ngx-bootstrap/modal그리고 새로운 것을 클릭합니다.ConfirmationComponent:
가드
을모달을 - 사용자 정의 ('bootstrap' - 새로사자정용운confirm로수함▁(▁that'▁-을표▁function▁with▁')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.confirm
<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();
}
}
그고새이후로운로리▁the로▁since▁new.ConfirmationComponent 됩니다않고를 사용하지 않고 표시됩니다.selectorhtml 템플릿에서는 루트에서 (아이비와 함께 더 이상 필요하지 않음)에 선언해야 합니다.app.module.ts(또는 루트 모듈의 이름을 지정하는 것).다음을 변경합니다.app.module.ts:
app.s.ts.
import { ModalModule } from 'ngx-bootstrap/modal';
import { ConfirmationComponent } from './confirmation.component';
@NgModule({
declarations: [
...
ConfirmationComponent
],
imports: [
...
ModalModule.forRoot()
],
entryComponents: [ConfirmationComponent] // Only when using old ViewEngine
2020년 6월 답변:
이 시점까지 제안된 모든 솔루션은 Angular's의 중요한 알려진 결함을 다루지 않습니다.canDeactivate가드:
- 사용자는 브라우저에서 '뒤로' 버튼을 클릭하고, 대화상자가 표시되며, 사용자는 '취소'를 클릭합니다.
- 사용자가 '뒤로' 버튼을 다시 클릭하면 대화 상자가 표시되고 사용자가 확인을 클릭합니다.
- 참고: 사용자는 2번 뒤로 탐색되어 앱에서 완전히 삭제될 수도 있습니다.
이것은 여기서, 여기서, 그리고 여기서 자세히 논의되었습니다.
이 문제를 안전하게 해결할 수 있는 문제에 대한 제 솔루션을 여기에서 확인하십시오*.이것은 Chrome, Firefox 및 Edge에서 테스트되었습니다.
중요 주의: 이 단계에서는 뒤로 버튼을 클릭하면 앞으로 이동 기록은 삭제되지만 뒤로 이동 기록은 유지됩니다.이 솔루션은 이전 내역을 보존하는 것이 중요한 경우에는 적합하지 않습니다.저의 경우 양식과 관련하여 일반적으로 마스터 세부 라우팅 전략을 사용하므로 이전 내역을 유지하는 것은 중요하지 않습니다.
Angular 15의 경우 클래스 기반 경로 가드가 더 이상 사용되지 않으며 기능 기반 경로 가드로 대체되었습니다.자세한 내용은 이 링크를 참조하십시오.
저는 @stewdebaker의 훌륭한 솔루션을 사용하여 필요한 변화를 만들었습니다.가드 자체만 변경되고 모듈 업데이트가 필요하지 않습니다.
구성요소(@stewdebaker의 변경 사항 없음)
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 { CanDeactivateFn, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
// Full solution found here: https://stackoverflow.com/a/41187919/74276
// and then changed to use the function-based method of doing route guards
// Updated solution found here: https://stackoverflow.com/a/75769104/74276
export interface ComponentCanDeactivate {
canDeactivate: () => boolean | Observable<boolean>;
}
export const PendingChangesGuard: CanDeactivateFn<ComponentCanDeactivate> = (
component: ComponentCanDeactivate
): Observable<boolean | UrlTree> => {
return new Observable<boolean | UrlTree>((obs) => {
// if there are no pending changes, just allow deactivation; else confirm first
return component.canDeactivate()
? obs.next(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
obs.next(
confirm(
'WARNING: You have unsaved changes. Press Cancel to go back and save these changes, or OK to lose these changes.'
)
);
});
};
경로(@stewdebaker의 경로에서 변경 사항 없음)
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] },
];
모듈
(기능 기반 경로 보호를 위해 모듈 변경 필요 없음)
솔루션이 예상보다 쉬웠습니다. 사용하지 마십시오.href각도 라우팅 사용으로 처리되지 않기 때문입니다.routerLink대신 지시합니다.
언급URL : https://stackoverflow.com/questions/35922071/warn-user-of-unsaved-changes-before-leaving-page
'programing' 카테고리의 다른 글
| AWS 람다 함수가 다른 함수를 호출할 수 있습니까? (0) | 2023.05.14 |
|---|---|
| 내부의.SQL Azure의 Net Framework 데이터 공급자 오류 6 (0) | 2023.05.14 |
| 생성자와 ngOnInit의 차이점 (0) | 2023.05.09 |
| 왜 그럴까요?수집이 null인 경우 각 루프 스로우 NullRefException에 대한 NET? (0) | 2023.05.09 |
| 시작 시 단일 양식 숨기기 (0) | 2023.05.09 |