diff --git a/apps/forms/48-avoid-losing-form-data/src/app/app.routes.ts b/apps/forms/48-avoid-losing-form-data/src/app/app.routes.ts index 84be34b9a..b135e2fe4 100644 --- a/apps/forms/48-avoid-losing-form-data/src/app/app.routes.ts +++ b/apps/forms/48-avoid-losing-form-data/src/app/app.routes.ts @@ -1,4 +1,5 @@ import { Route } from '@angular/router'; +import { canDeactivateGuard } from './can-deactivate.guard'; import { JoinComponent } from './pages/join.component'; import { PageComponent } from './pages/page.component'; @@ -11,6 +12,7 @@ export const appRoutes: Route[] = [ { path: 'form', loadComponent: () => JoinComponent, + canDeactivate: [canDeactivateGuard], }, { path: 'page-1', diff --git a/apps/forms/48-avoid-losing-form-data/src/app/can-deactivate.guard.ts b/apps/forms/48-avoid-losing-form-data/src/app/can-deactivate.guard.ts new file mode 100644 index 000000000..3f54cee3e --- /dev/null +++ b/apps/forms/48-avoid-losing-form-data/src/app/can-deactivate.guard.ts @@ -0,0 +1,18 @@ +import { CanDeactivateFn, UrlTree } from '@angular/router'; +import { Observable } from 'rxjs'; + +export type CanDeactivateType = + | Observable + | Promise + | boolean + | UrlTree; + +export interface CanComponentDeactivate { + canDeactivate: () => CanDeactivateType; +} + +export const canDeactivateGuard: CanDeactivateFn = ( + component: CanComponentDeactivate, +) => { + return component.canDeactivate ? component.canDeactivate() : true; +}; diff --git a/apps/forms/48-avoid-losing-form-data/src/app/pages/join.component.ts b/apps/forms/48-avoid-losing-form-data/src/app/pages/join.component.ts index 51449a7fb..2fdaf87ab 100644 --- a/apps/forms/48-avoid-losing-form-data/src/app/pages/join.component.ts +++ b/apps/forms/48-avoid-losing-form-data/src/app/pages/join.component.ts @@ -1,8 +1,18 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { Dialog, DialogModule } from '@angular/cdk/dialog'; +import { + ChangeDetectionStrategy, + Component, + HostListener, + inject, + viewChild, +} from '@angular/core'; +import { map } from 'rxjs'; +import { CanComponentDeactivate } from '../can-deactivate.guard'; +import { AlertDialogComponent } from '../ui/dialog.component'; import { FormComponent } from '../ui/form.component'; @Component({ - imports: [FormComponent], + imports: [FormComponent, DialogModule], template: `
@@ -12,4 +22,34 @@ import { FormComponent } from '../ui/form.component'; `, changeDetection: ChangeDetectionStrategy.OnPush, }) -export class JoinComponent {} +export class JoinComponent implements CanComponentDeactivate { + dialog = inject(Dialog); + + formComponent = viewChild(FormComponent); + + @HostListener('window:beforeunload', ['$event']) + handleBeforeUnload(event: BeforeUnloadEvent) { + const form = this.formComponent()?.form; + if (!form?.dirty || !form?.value) { + return; + } + + event.preventDefault(); + } + + canDeactivate = () => { + const form = this.formComponent()?.form; + + if (form?.dirty && form?.value) { + const dialogRef = this.dialog.open(AlertDialogComponent, { + role: 'alertdialog', + ariaDescribedBy: 'dialog-description', + ariaLabelledBy: 'dialog-title', + ariaModal: true, + }); + return dialogRef.closed.pipe(map((result) => !!result)); + } + + return true; + }; +} diff --git a/apps/forms/48-avoid-losing-form-data/src/app/ui/dialog.component.ts b/apps/forms/48-avoid-losing-form-data/src/app/ui/dialog.component.ts index 21db4d56f..4504bb066 100644 --- a/apps/forms/48-avoid-losing-form-data/src/app/ui/dialog.component.ts +++ b/apps/forms/48-avoid-losing-form-data/src/app/ui/dialog.component.ts @@ -1,24 +1,29 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { DialogRef } from '@angular/cdk/dialog'; +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; // NOTE : this is just the dialog content, you need to implement dialog logic @Component({ template: `