When user reaches a route in my application, which is protected by special guard, I'm redirecting him to a sign-in route, in order to perform authentication.
However, after successful authentication I wan't to redirect her back to a route she was initially reaching.
How do I preserve intermediate routing state in Angular and then redirect to it?
By routing state I mean the following:
After playing with the router a bit, I've finally managed to implement the solution I wanted. I'm going to share it here with you.
So here's the implementation of IntermediateNavigationService
:
import {Subscription} from 'rxjs/Subscription';
import {NavigationCancel, NavigationEnd, Router} from '@angular/router';
import {Injectable} from '@angular/core';
@Injectable()
export class IntermediateNavigationService {
private savedUrl: string;
private routerSubscription: Subscription;
constructor (private router: Router) {
}
startWatch () {
this.routerSubscription = this.router.events
.subscribe(event => {
if (event instanceof NavigationCancel) {
// Saving URL from canceled route.
this.saveUrl(event.url);
} else if (event instanceof NavigationEnd) {
// If user navigates away from sign-in page, clearing saved URL.
if (!event.url.match(/^\/sign-in/)) {
if (this.hasSavedUrl()) {
this.clearSavedUrl();
}
}
}
})
;
}
stopWatch () {
this.routerSubscription.unsubscribe();
}
saveUrl (url: string) {
this.savedUrl = url;
}
hasSavedUrl () {
return !!this.savedUrl;
}
getSavedUrl () {
return this.savedUrl;
}
clearSavedUrl () {
this.savedUrl = null;
}
goToSavedUrl (): Promise<boolean> {
return this.router.navigateByUrl(this.savedUrl).then(result => {
if (result) {
this.clearSavedUrl();
}
return result;
});
}
}
The idea behind this service is pretty simple. When activated by startWatch()
method (you should do it as early as possible in application lifecycle, for example in AppComponent constructor), it starts to monitor router events specifically filtering the NavigationCancel
and NavigationEnd
events.
When NavigationCancel
happens, it means, that our authentication route guard prevented the navigation to a target route. Therefore we are saving the skipped URL inside of the service private variable.
When NavigationEnd
happens, we check if user navigated away from our sign-in route. In this case we are no longer interested in preserving the saved URL, so we are clearing it. Otherwise it could lead to strange behavior, when user is redirected to URL he is no longer interested in.
After successful sign-in, we should just issue this code:
if (this.intermediateNavigationService.hasSavedUrl()) {
this.intermediateNavigationService.goToSavedUrl();
} else {
this.navigationService.redirectAfterSignIn();
}
Is short: we just checking if there is a saved URL, then we navigating to it, if not redirecting to the default one.
And if you are no longer interested in monitoring the state at some point, just call to stopWatch()
in order to cancel the router events subscription. It could be done after successful sign-in actually to preserve resources (if you are not going to use this service for similar behavior which is not related to authentication of course).
And there is no need to call startWatch()
if user is already authenticated.
Here's how your AppComponent
could look like:
import {Component as NgComponent} from '@angular/core';
import {AuthenticationStateService} from './authentication/authentication-state.service';
import {IntermediateNavigationService} from './services/intermediate-navigation.service';
@NgComponent({})
export class MyAppComponent {
constructor (
private authenticationStateService: AuthenticationStateService,
private intermediateNavigationService: IntermediateNavigationService
) {
// Enabling intermediate URL handling.
if (!this.authenticationStateService.isAuthenticated()) {
this.intermediateNavigationService.startWatch();
}
// Listening for authentication event.
this.authenticationStateService.onAuthenticated().subscribe(() => {
this.intermediateNavigationService.stopWatch()
});
}
}
I hope it will help someone.
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