Reputation: 141
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
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
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