Jamie
Jamie

Reputation: 141

Angular 4 canDeactivate fails if back button is hit twice in a row

I am attempting to implement a back button guard in Angular 4 for the first time. I am trying to use a service and canDeactivate.

I'm using the following service (code I found on the web, not my original code):

import { Injectable } from '@angular/core';
import { CanDeactivate } from '@angular/router';
import { Observable } from 'rxjs/Observable';

export interface CanComponentDeactivate {
    canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean;
}

@Injectable()
export class CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate> {

    canDeactivate(component: CanComponentDeactivate) {
        return component.canDeactivate ? component.canDeactivate() : true;
    }

}

Then in my routing module, I have the following path that uses canDeactivate:

{ path: 'contacts/:id/edit', canActivate: [AuthGuard], component: ContactEditComponent, data: { title: 'Edit Contact' }, canDeactivate: [CanDeactivateGuard] }

Finally, in the component where I want back button routing protection, I have the following method:

canDeactivate() {
  if (this.editMode) {
    return window.confirm('Discard changes?');
  }
  return true;
}

I was expecting that each time I attempted to hit the back button I would receive a pop-up with the 'Discard changes?' message.

What's happening is if I hit the back button, the pop-up alert occurs as expected. If I select 'cancel' the app won't navigate to the previous component. But, if I hit the back button a subsequent time, the app navigates back two components (in other words, to the 'page' before the 'page' before the 'page' I'm viewing).

Just for testing purposes I tried replacing if (this.editMode) with if (true) just to confirm that the state wasn't getting lost. There was no change in behavior.

Upvotes: 2

Views: 3798

Answers (2)

Vinamra Jain
Vinamra Jain

Reputation: 11

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

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

canDeactivate(component: CanComponentDeactivate, currentRoute: ActivatedRouteSnapshot) {
    const confirmation = window.confirm('Is it OK?');
    if(!confirmation) {
        const currentUrlTree = this.router.createUrlTree([], currentRoute);
        const currentUrl = currentUrlTree.toString();
        this.location.go(currentUrl);
    }

    return of(confirmation);
}

Upvotes: 1

Jamie
Jamie

Reputation: 141

This seems to be a known Angular bug that has been fixed and is awaiting conflict resolution before it's merged into the Angular GitHub master branch.

https://github.com/angular/angular/pull/18135

Upvotes: 2

Related Questions