I've created a route guard with CanDeactivate that determines if a user can navigate away from a page if they have any unsaved changes, and triggers a MatDialog modal if any unsaved changes exist. I've looked at plenty of guides and similar threads and my code is working (for the most part). See below:
Here's the route guard, it calls the component's confirmRouteChange function, if it has one, and returns the result, an Observable<boolean>
:
@Injectable({
providedIn: 'root'
})
export class UnsavedChangesGuard implements CanDeactivate<DirtyComponent> {
canDeactivate(component: DirtyComponent): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
return component?.confirmRouteChange ? component.confirmRouteChange() : true;
}
}
Here's the implementation of confirmRouteChange, it just opens the MatDialog if the form is dirty and returns the Observable that notifies when the dialog is closed:
confirmRouteChange() {
if (this.isDirty) {
let dialogRef = this.matDialog.open(AlertModalComponent, {
data: {
msg: 'Your changes have not been saved. If you leave this page, your changes will be lost.',
title: 'Changes have not been saved',
class: 'save-changes'
}
});
return dialogRef.afterClosed();
} else {
return true;
}
}
And here's the implementation of my modal's save/close options:
save() {
this.dialogRef.close(false);
}
close() {
this.dialogRef.close(true);
}
So here's my problem: when I navigate away with unsaved changes, the modal pops up (great), the app navigates properly according to the choice selected in the modal (great); however, behind the modal I can see that the rest of my app navigates away from the page EXCEPT for the component that the route guard is placed on. So if I attempt to navigate to the homepage, I can see all of the homepage AND the component that with my form of unsaved changes. It's as if it starts navigating, stops, and THEN it waits on the user's response. If I use the native confirm()
dialog, it works perfectly meaning the app effectively freezes while it waits for the user response. I believe it's because if I log what confirm()
returns, it does not return anything until the user selects something. On the other hand, dialogRef.afterClosed()
returns the Observable immediately, which I guess triggers navigation, and then the app stops and waits for the user's response.
I think there's something wrong with my usage of the modal, but I'm not sure what. Any help is greatly appreciated!
Edit: I think the return dialogRef.afterClosed()
statement is executing before the dialog has finished opening, causing the navigation to start and then stop.