From 771024ec2ea946c79b774167047036c50ac15d8b Mon Sep 17 00:00:00 2001 From: lukasss88 Date: Sat, 8 Nov 2025 19:34:54 +0100 Subject: [PATCH] feat: fix angular back button navigation challenge --- .../src/app/app.component.ts | 4 +- .../src/app/app.config.ts | 7 ++++ .../src/app/app.routes.ts | 3 ++ .../src/app/can-decativate.guard.ts | 42 +++++++++++++++++++ .../sensitive-action.component.ts | 15 +++++++ 5 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 apps/angular/55-back-button-navigation/src/app/can-decativate.guard.ts diff --git a/apps/angular/55-back-button-navigation/src/app/app.component.ts b/apps/angular/55-back-button-navigation/src/app/app.component.ts index baffdae25..3cec76af7 100644 --- a/apps/angular/55-back-button-navigation/src/app/app.component.ts +++ b/apps/angular/55-back-button-navigation/src/app/app.component.ts @@ -1,8 +1,8 @@ import { Component } from '@angular/core'; -import { RouterLink, RouterOutlet } from '@angular/router'; +import { RouterOutlet } from '@angular/router'; @Component({ - imports: [RouterOutlet, RouterLink], + imports: [RouterOutlet], selector: 'app-root', templateUrl: './app.component.html', }) diff --git a/apps/angular/55-back-button-navigation/src/app/app.config.ts b/apps/angular/55-back-button-navigation/src/app/app.config.ts index 440cdf2c3..af811b1d4 100644 --- a/apps/angular/55-back-button-navigation/src/app/app.config.ts +++ b/apps/angular/55-back-button-navigation/src/app/app.config.ts @@ -1,4 +1,5 @@ import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; +import { MAT_DIALOG_DEFAULT_OPTIONS } from '@angular/material/dialog'; import { provideRouter } from '@angular/router'; import { APP_ROUTES } from './app.routes'; @@ -6,5 +7,11 @@ export const appConfig: ApplicationConfig = { providers: [ provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(APP_ROUTES), + { + provide: MAT_DIALOG_DEFAULT_OPTIONS, + useValue: { + closeOnNavigation: false, + }, + }, ], }; diff --git a/apps/angular/55-back-button-navigation/src/app/app.routes.ts b/apps/angular/55-back-button-navigation/src/app/app.routes.ts index 7deecd57a..9ffbb8c4c 100644 --- a/apps/angular/55-back-button-navigation/src/app/app.routes.ts +++ b/apps/angular/55-back-button-navigation/src/app/app.routes.ts @@ -1,4 +1,5 @@ import { Routes } from '@angular/router'; +import { CanDeactivateGuard } from './can-decativate.guard'; import { HomeComponent } from './home/home.component'; import { SensitiveActionComponent } from './sensitive-action/sensitive-action.component'; import { SimpleActionComponent } from './simple-action/simple-action.component'; @@ -16,9 +17,11 @@ export const APP_ROUTES: Routes = [ { path: 'simple-action', component: SimpleActionComponent, + canDeactivate: [CanDeactivateGuard], }, { path: 'sensitive-action', component: SensitiveActionComponent, + canDeactivate: [CanDeactivateGuard], }, ]; diff --git a/apps/angular/55-back-button-navigation/src/app/can-decativate.guard.ts b/apps/angular/55-back-button-navigation/src/app/can-decativate.guard.ts new file mode 100644 index 000000000..ea311a053 --- /dev/null +++ b/apps/angular/55-back-button-navigation/src/app/can-decativate.guard.ts @@ -0,0 +1,42 @@ +import { inject, Injectable } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; +import { + CanDeactivate, + GuardResult, + MaybeAsync, + UrlTree, +} from '@angular/router'; +import { Observable } from 'rxjs'; + +export type CanDeactivateType = + | Observable + | Promise + | boolean + | UrlTree; + +export interface CanComponentDeactivate { + canDeactivate?: () => CanDeactivateType; +} + +@Injectable({ + providedIn: 'root', +}) +export class CanDeactivateGuard + implements CanDeactivate +{ + readonly #dialog = inject(MatDialog); + + canDeactivate(component: CanComponentDeactivate): MaybeAsync { + return component.canDeactivate + ? component.canDeactivate() + : this.defaultCanDeactivate(); + } + + defaultCanDeactivate(): boolean { + if (this.#dialog.openDialogs.length === 0) { + return true; + } + this.#dialog.closeAll(); + return false; + } +} diff --git a/apps/angular/55-back-button-navigation/src/app/sensitive-action/sensitive-action.component.ts b/apps/angular/55-back-button-navigation/src/app/sensitive-action/sensitive-action.component.ts index a97282c33..3d7d81366 100644 --- a/apps/angular/55-back-button-navigation/src/app/sensitive-action/sensitive-action.component.ts +++ b/apps/angular/55-back-button-navigation/src/app/sensitive-action/sensitive-action.component.ts @@ -1,6 +1,7 @@ import { Component, inject } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatDialog } from '@angular/material/dialog'; +import { CanDeactivateType } from '../can-decativate.guard'; import { DialogComponent } from '../dialog/dialog.component'; @Component({ @@ -16,4 +17,18 @@ export class SensitiveActionComponent { width: '250px', }); } + + canDeactivate: () => CanDeactivateType = () => { + if (this.#dialog.openDialogs.length === 0) { + return true; + } + + const confirmation = confirm( + 'You have open dialogs. Are you sure you want to leave this page?', + ); + if (confirmation) { + this.#dialog.closeAll(); + } + return confirmation; + }; }