Reputation: 380
I am using Angular 5 ad have Implemented a CanDeactivateGuard for a component to pop up a modal if there are some unsaved changes:
export interface CanComponentDeactivate {
canDeactivate: (nextStateUrl: string) => Observable<boolean> | boolean;
}
@Injectable()
export class CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate> {
canDeactivate(
component: CanComponentDeactivate,
currentRoute: ActivatedRouteSnapshot,
currentState: RouterStateSnapshot,
nextState?: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
return component && component.canDeactivate
? component.canDeactivate(nextState.url)
: true;
}
}
I have added this guard to page2 and it works perfectly if I navigate from page 1 to page2 and make some changes and try to navigate away. However, if I stay in page2 and refresh the page and then make some changes, and try to navigate away, the canDeactivate method in the guard will be called, but the component value is null, so it returns true without showing the confirmation modal. Or if I navigate from page2 to another page which is not loaded yet. Note that all pages are lazyloaded and each page has its route module.
I have added the guard to page2 module the same way done here: http://plnkr.co/edit/z2OqgTXTiPpTgXcmNiDM?p=preview
I also tried to add the guard to main guard, but didn't work either.
Is there any reason when I refresh the component is null but when I navigate from other pages to page 2, the component is not in the guard.
Is here any fix for it?
Thanks
Upvotes: 4
Views: 6555
Reputation: 472
There's a few options. I could only get my application to warn of pending changes when doing page refreshes by using router-outlet. See https://stackoverflow.com/a/51145053/2525272.
Depending on your environment, you may be able to expand on the CanDeactivate guard with something like this - https://medium.com/front-end-weekly/angular-how-keep-user-from-lost-his-data-by-accidentally-leaving-the-page-before-submit-4eeb74420f0d. Or this - https://code.i-harness.com/en/q/2242097. This was also discussed here and what I used - Warn user of unsaved changes before leaving page. The key is importing HostListener into Angular to handle/intercept the browser's beforeunload event so it can go through our route guard to make sure you need to prompt the user if the page is dirty. Simply adding the following will always prompt the user, whether there's changes or not, so it's misleading/confusing. It will also always prompt the user if they close their tab or browser, regardless of whether they need to be prompted due to unsaved changes.
// prevent losing changes with page refresh
window.addEventListener("beforeunload", function (e) {
var confirmationMessage = "\o/";
e.returnValue = confirmationMessage; // Gecko, Trident, Chrome 34+
return confirmationMessage; // Gecko, WebKit, Chrome <34
});
Or, introduce a new CanActivate guard like this - https://www.bennadel.com/blog/3368-prevent-routing-to-secondary-view-if-page-refresh-in-angular-5-0-0.htm.
Also, I really liked this page - https://www.concretepage.com/angular-2/angular-candeactivate-guard-example for a good reference on creating a reusable route guard service.
Upvotes: 2