question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

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:open
  • Created 5 years ago
  • Reactions:27
  • Comments:5 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
jasonadencommented, Apr 4, 2019

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).

1reaction
atscottcommented, Jun 22, 2022

This would be possible after introducing a RedirectCommand (https://github.com/angular/angular/pull/45023). Resolvers that return the Router’s RedirectCommand would be assumed to be distinctly indicating a redirect rather than resolved data.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How can I route to a child route based on the resolved route ...
The Resolver in the root module provides the data to which component should be redirected to. AppModule: const routes = [ { path:...
Read more >
Better Redirects in Angular Route Guards | juri.dev
Learn how to properly redirect in an Angular route guard · Route Guards - A quick primer · Blocking is not enough ·...
Read more >
Router - Angular
A service that provides navigation among views and URL manipulation ... In order to reload routed components on same url navigation, you need...
Read more >
Testing Angular route guards with the RouterTestingModule
We also need to verify that when the user is logged in, ... the Router service that the authentication guard uses to redirect...
Read more >
The 7-step process of Angular router navigation
A URL tree is a data structure that will later help Angular router ... Angular router has a URL tree with a potential...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found