I need to prevent the user from backward navigation in some parts of an app I am building. So far I am using this method:
ngOnInit() {
history.pushState(null, null, location.href);
window.onpopstate = function(event) {
history.go(1);
};
}
ngOnDestroy() {
window.onpopstate = function(event) {
history.go();
};
}
This is working great except on iOS chrome and safari. I've also tried:
history.replaceState(null, document.title, location.pathname);
in ngOnInit with not luck. Can someone enlighten my on how browsers on these mobile devices are using history and/or popstate differently than on windows/macOS versions of browsers?
Instead of trying to implement different browser-specific solutions, I would think about Angular's CanDeactivate
guard.
Suppose you have a service (let's call it NavigatorService
) that always stores the previous route:
@Injectable()
export class NavigatorService{
private previousRoute:string = null;
private currentRoute:string = null;
/** Listen to and log new route paths */
constructor(private router:Router){
router.events.filter(e => e instanceof NavigationEnd).subscribe(
e => {
this.previousRoute = this.currentRoute;
this.currentRoute = e['url'];
}
)
}
/** Checks whether the next route corresponds to the previous route */
isGoingBack(nextState:RouterStateSnapshot){
return nextState.url === this.previousRoute;
}
}
Next create a CanDeactivateGuard that will rely on this service to determine whether to allow the user to navigate away from the current view:
@Injectable()
export class BackwardGuard implements CanDeactivate<any> {
// Inject the service needed
constructor(navigatorService:NavigatorService){}
// Angular 4 provides these arguments to any CanDeactivate guard
// see https://angular.io/api/router/CanDeactivate#interface-overview
canDeactivate(component:any, currentRoute:ActivatedRouteSnapshot,
currentState:RouterStateSnapshot, nextState:RouterStateSnapshot){
// Allow navigation only if the user is not going back
return !this.navigatorService.isGoingBack(nextState);
}
}
Finally, register this guard on the routes whose components you want to protect from backwards navigation:
appRoutes:Routes = [
{
path: 'some-path',
component: ProtectedComponent,
canDeactivate: [BackwardGuard]
}
];
There may be bugs in this untested code, but I think once you iron them out, it should work. Remember to provide NavigatorService
to your component's module (e.g: AppModule
) and to provide BackwardGuard
to the matching routing module (e.g.: AppRoutingModule
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With