Routingintermediate
Guarding Unsaved Changes
Explain how a CanDeactivate guard prompts a user before navigating away from a form with unsaved changes.
One of the most common real-world UX requirements — warning a user before they navigate away from a form with unsaved edits — is implemented in Angular through a CanDeactivate guard, which is essentially the mirror image of CanActivate: instead of deciding whether navigation into a route is allowed, it decides whether navigation away from the currently active route is allowed to proceed.
It's like a hotel checkout clerk who always asks 'are you sure you've packed everything?' before letting you leave the room — the clerk doesn't know your suitcase contents directly, but trusts you (the component) to answer honestly when asked.
Key Concepts
1
The functional CanDeactivateFn<T> receives the component instance being deactivated (along with the current and next route/state), which is the interesting part: unlike other guards, this one is deliberately given a reference to the actual component so it can ask that component directly whether it has unsaved changes, typically through a shared interface the component implements (e.g., a hasUnsavedChanges(): boolean method or a canDeactivate(): boolean method by convention).
CanDeactivateFn<T>hasUnsavedChanges(): booleancanDeactivate(): boolean
2
A well-designed version defines a small interface (like interface CanComponentDeactivate { canDeactivate: () => boolean | Observable<boolean> }) that any component wanting this protection implements, and a single generic guard function that calls component.canDeactivate() and returns its result — this keeps the guard itself completely reusable across many different forms, rather than writing a bespoke guard per feature.
interface CanComponentDeactivate { canDeactivate: () => boolean | Observable<boolean> }component.canDeactivate()
3
Interviewers sometimes push on the UX detail: the guard itself typically triggers a native confirm() dialog or a custom modal asking "You have unsaved changes — leave anyway?", and the guard's return value (or resolved Observable/Promise) directly reflects the user's choice in that dialog — true to proceed with navigation, false to stay on the current page and let the user continue editing.
confirm()ObservablePromise