Router Resolve<T> should have official support for UrlTree based redirection
See original GitHub issue🚀 feature request
Relevant Package
@angular router
Description
I see that in the docs it is recommended to do the following to cancel a navigation event in a Resolve<T>
route data resolver.
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Crisis> | Observable<never> {
let id = route.paramMap.get('id');
return this.cs.getCrisis(id).pipe(
take(1),
mergeMap(crisis => {
if (crisis) {
return of(crisis);
} else { // id not found
this.router.navigate(['/crisis-center']);
return EMPTY;
}
})
);
}
While this does work it generates a pretty gnarly NavigationCancel
event that basically says ‘You broke my internal state’:
NavigationCancel {id: 5, url: "/crisis-center/4444", reason: "Navigation ID 5 is not equal to the current navigation id 6"}
id: 5
reason: "Navigation ID 5 is not equal to the current navigation id 6"
url: "/crisis-center/4444"
This is because we have overlapping navigation events, and the original navigation is cancelled because we essentially triggered the router’s panic mode.
Describe the solution you’d like
Angular 7.1 introduced the option of returning a UrlTree
from a canActivate
, and I think something similar should be added to Resolve<T>
for feature parity.
A Resolve
may fail for many reasons, but we should have a clean option to redirect within the resolver - especially in cases where it is impossible to know the final destination until you’ve attempted to get the data.
I think perhaps the signature of resolve
needs to become something like :
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<T | UrlTree> | Promise<T | UrlTree> | T | UrlTree;
Describe alternatives you’ve considered
Yes, delving into the code showed me that I could throw an error that satisfies the isNavigationCancelingError()
type-guard and not only would it give me a nicer NavigationCancel
event it would also allow me to pass a url: UrlTree
parameter which will then be navigated to on my behalf.
throw { ngNavigationCancelingError: true, url: this.router.createUrlTree(newUrl) };
While this actually works quite well - and gives the following ‘nice’ event it isn’t really supported since I have to use the magic internal property name - and also not every reason for aborting a Resolve is an error condition.
NavigationCancel {id: 11, url: "/account/orders/latest", reason: undefined}
id: 11
reason: undefined
url: "/account/orders/latest"
The other alternative is what is suggested in the docs, but the error (Navigation ID 5 is not equal to the current navigation id 6
) from doing that just makes it look like something is broken.
I think the mechanics of this are basically already there, expecially with the new functionality in 7.1 to handle a UrlTree
. There is also plenty of need for such a feature on Stackoverflow…
Issue Analytics
- State:
- Created 5 years ago
- Reactions:27
- Comments:5 (4 by maintainers)
Agreed, this should be added as a feature. I’ll assign to myself, but I know I won’t be able to get to this until some time after version 8 is finalized (probably next month). If anyone in the community would like to pick this up, that would be great. It could be modeled on the changes we did to implement this feature in Guards (#26521 and #26478).
This would be possible after introducing a
RedirectCommand
(https://github.com/angular/angular/pull/45023). Resolvers that return the Router’sRedirectCommand
would be assumed to be distinctly indicating a redirect rather than resolved data.