Skip to main content

Lab 08: Deactivate Guard

πŸ“– Resources​

πŸš€ Starter Code​

step-8-album-wholesale-v16-auth-guard

In this lab, you'll prevent users from accidentally losing unsaved form data by implementing a CanDeactivate guard. You'll create a functional guard that prompts users for confirmation, implement the deactivation logic in your component, and optionally replace browser confirm dialogs with Material Dialog.

πŸ“ Instructions​

Step 1: Create Deactivate Guard​

Create a functional guard:

import { CanDeactivateFn } from '@angular/router';

export interface CanComponentDeactivate {
canDeactivate: () => boolean;
}

export const canDeactivateGuard: CanDeactivateFn<CanComponentDeactivate> = (component) => {
if (component.canDeactivate && !component.canDeactivate()) {
return confirm('You have unsaved changes. Leave anyway?');
}
return true;
};

Step 2: Implement in Component​

Add canDeactivate method to component:

export class AlbumAddComponent implements CanComponentDeactivate {
private formSubmitted = false;

canDeactivate(): boolean {
return !this.albumForm.dirty || this.formSubmitted;
}

saveAlbum() {
this.formSubmitted = true;
// Save logic...
}
}

Step 3: Apply to Route​

Add guard to route:

const routes: Routes = [
{
path: 'albums/add',
component: AlbumAddComponent,
canDeactivate: [canDeactivateGuard]
}
];

Bonus Step: Use MatDialog Instead of confirm()​

Replace browser confirm() with Material Dialog:

import { inject } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { ConfirmDialogComponent } from './confirm-dialog.component';

export const canDeactivateGuard: CanDeactivateFn<CanComponentDeactivate> = (component) => {
if (component.canDeactivate && !component.canDeactivate()) {
const dialog = inject(MatDialog);

return dialog.open(ConfirmDialogComponent, {
data: { message: 'You have unsaved changes. Leave anyway?' }
}).afterClosed();
}
return true;
};

Simple confirmation dialog component:

@Component({
selector: 'app-confirm-dialog',
template: `
<h2 mat-dialog-title>Confirm</h2>
<mat-dialog-content>{{ data.message }}</mat-dialog-content>
<mat-dialog-actions>
<button mat-button [mat-dialog-close]="false">Cancel</button>
<button mat-button [mat-dialog-close]="true" color="warn">Leave</button>
</mat-dialog-actions>
`
})
export class ConfirmDialogComponent {
data = inject(MAT_DIALOG_DATA);
}