6

I'm implementing CanDeactivate functionality in one of my main components. To test it I've made it to always return false so the route must not change.

This is the CanDeactivate implementation in which the call to component.canDeactivate() returns a Promise resolved to false:

@Injectable()
export class CanDeactivateNewRecord implements 
CanDeactivate<NewRecordComponent> {
    canDeactivate(
        component: NewRecordComponent,
        currentRoute: ActivatedRouteSnapshot,
        currentState: RouterStateSnapshot,
        nextState: RouterStateSnapshot ): 
        Observable<boolean>|Promise<boolean>|boolean {

        return component.canDeactivate();
    }
}

This is the fragment with definition of the routes for the module:

const recordsRoutes: Routes = [
    {
        path: 'nou',
        component: NewRecordComponent,
        canDeactivate: [CanDeactivateNewRecord]
    },{
        path: ':id',
        component: RecordComponent
    }
];

When I use the method back of the service Location from @angular/common to navigate to a previous page there are two different situations:

  • if the previous location was managed by the Angular router the navigation is prevented and the application stay at the route of this component,
  • if the previous location was outside the application (for example if the url of the route for this component was introduced directly in the browser navigation bar) it goes outside the applicatin and loads the previous page.

Even if the previous location was managed by the router, calling location.back() enough times (as many times as the length of the history of navigation through the application) it makes the navigation return to the page before the start of the application.

What's wrong with this?

francadaval
  • 2,451
  • 3
  • 26
  • 36
  • may be register onbeforeunload event handler? – Julia Passynkova May 17 '17 at 21:53
  • I've seen in [this question answers](http://stackoverflow.com/questions/35922071/warn-user-of-unsaved-changes-before-leaving-page) how to manage, with this event, when the users tries to navigate to an external url or closes the window. I'm starting to think that I must avoid and find a workaruond to the use of `location->back()`. – francadaval May 18 '17 at 09:16
  • @francadaval What was your final solution? I'm trying to prevent the user from going back. – Anthony Oct 09 '17 at 22:03
  • I have the same Issue. Did you find a work around? – Chuck Nov 14 '18 at 15:08
  • 2
    This is an Angular bug https://github.com/angular/angular/issues/13586 – Chuck Nov 14 '18 at 15:43

2 Answers2

4

I know this is SUPER late, but I had this exact same issue and figured I'd leave this here for posterity. As another stated, it is a known Angular issue that has yet to be fixed. There is a workaround that I was able to make use of, it can be found here: github

Implementation for your code would look something like this:

@Injectable()
export class CanDeactivateNewRecord implements CanDeactivate<NewRecordComponent> {
    constructor(
        private readonly location: Location;
        private readonly router: Router;
    ){}
    canDeactivate(component: NewRecordComponent, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState: RouterStateSnapshot ): Observable<boolean>|Promise<boolean>|boolean {
        if(component.canDeactivate()){
            return true
        }else{
            const currentUrlTree = this.router.createUrlTree([], currentRoute);
            const currentUrl = currentUrlTree.toString();
            this.location.go(currentUrl)
            return false
        }
    }
}

Grabs the most recent route and inserts back into the url tree if canDeactivate returns false.

Rharris389
  • 89
  • 8
0

At first, I thought https://stackoverflow.com/a/65525803/857653 would work for us. But then I discovered, that in some cases we would need to know if the user hit "back" or there was some other kind of navigation going on. Then I discovered a better solution for us:

Router Property "canceledNavigationResolution"

Since Angular 12 there is a router config property, which was the solution in our application with Angular 15 (see also https://github.com/angular/angular/issues/13586#issuecomment-898704702)

In our main.ts:

provideRouter(APP_ROUTES,
  withRouterConfig({
    canceledNavigationResolution: 'computed',
  })
)
Manuel
  • 801
  • 9
  • 12