6

I am facing some issue with canDeactivate() whenever it returns false it is changing the window history as when it became true and if i hit the back button. I am navigating to some other URL or out of the app itself.

Please help me

Deepender Sharma
  • 460
  • 1
  • 5
  • 25

4 Answers4

9

Here is the issue, but it still isn't fixed.

As a workaround, you can manually put the active url back to the history:

export class CanDeactivateGuard implements CanDeactivate<any> {
    constructor(
        private readonly location: Location,
        private readonly router: Router
    ) {}

    canDeactivate(component: any, currentRoute: ActivatedRouteSnapshot): boolean {
        if (myCondition) {
            const currentUrlTree = this.router.createUrlTree([], currentRoute);
            const currentUrl = currentUrlTree.toString();
            this.location.go(currentUrl);
            return false;
        } else {
            return true;
        }
    }
}
Valeriy Katkov
  • 33,616
  • 20
  • 100
  • 123
  • 1
    This fix works great when the de-activation was triggered by the history.back, but when triggering normal navigation in angular the URL never changes, so it's good idea to check if you are not already on that path before pushing the currentUrl, e.g.: `if(!this.location.path().endsWith(currentUrl)) { this.location.go(currentUrl); }` – edrian Apr 18 '21 at 16:10
  • Angular fixed the issue as pointed out by @MeysamSahragard - https://stackoverflow.com/a/76027002/6301243 – jake Jul 17 '23 at 18:47
2

The issue is still present with Angular routing and below is what worked for me.

Trick is to use this.router.navigate([currentUrl], { skipLocationChange: true });

Full code:

export class CanDeactivateGuard implements CanDeactivate<any> {

  constructor(
    private location: Location,
    private router: Router
  ) { }

  canDeactivate(component: any,
    currentRoute: ActivatedRouteSnapshot, 
    currentState: RouterStateSnapshot): boolean {

    if(canDeactivateCondition) {
      return true;
    } else {
      const currentUrl = currentState.url;
      if (this.location.isCurrentPathEqualTo(currentUrl)) {
        // https://github.com/angular/angular/issues/13586
        this.router.navigate([currentUrl], { skipLocationChange: true });
      } else {
        // A browser button has been clicked or location.back()/forward() invoked. Restore browser history
        history.pushState(null, null, location.href);
      }

      return false;
    }
  }
}
Nalin
  • 93
  • 1
  • 7
1

This is a know bug in Angular: https://github.com/angular/angular/issues/13586

There is a lot a workaround proposed but all of them seem to break other parts.

Appears to be fixed now in Angular 12.1.2: https://github.com/angular/angular/issues/13586#issuecomment-881627456

Jon
  • 218
  • 7
  • 18
1

In angular 15 I added canceledNavigationResolution: 'computed' in Router Module configs and the problem was solved.

@NgModule({
  imports: [
    RouterModule.forRoot(routes, {
      canceledNavigationResolution: 'computed',
    }),
  ],
  exports: [RouterModule],
})
export class AppRoutingModule {}