Skip to content

feat(router): allow passing an ActivatedRouteSnapshot for relative link resolution in Router.createUrlTree #43800

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

daiscog
Copy link

@daiscog daiscog commented Oct 11, 2021

The relativeTo property of the navigationExtras parameter in the createUrlTree method of the Router class may now be an ActivatedRoute or an ActivatedRouteSnapshot.
The latter is useful in CanActivate route guards when building an alternative UrlTree to navigate to, relative to the URL that the current navigation is attempting to access.

Fixes #22763

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • angular.io application / infrastructure changes
  • Other... Please describe:

What is the current behavior?

As reported in Issue Number: #22763, when implementing a CanActivate route guard, there is no way to return a UrlTree relative to the route that would otherwise have been activated, as the current ActivatedRoute is the previous navigation, and the next navigation is only available via the ActivatedRouteSnapshot given to the guard.

What is the new behavior?

This change allows passing an ActivatedRouteSnapshot to as the relativeTo value, thus enabling the following pattern in a route guard:

export class ExampleGuard implements CanActivate {
  constructor(private readonly router: Router) {}

  canActivate(next: ActivatedRouteSnapshot): UrlTree | boolean {
    return this.routeIsAvailable() || this.buildRedirectUrlTree(next);
  }

  private buildRedirectUrlTree(next: ActivatedRouteSnapshot): UrlTree {
    return this.router.createUrlTree('../default-place', {relativeTo: next});
  }

  private routeIsAvailable(): boolean {
    // check state to see if route available at this time and return true/false
    return true;
  }
}

Does this PR introduce a breaking change?

  • Yes
  • No

@google-cla google-cla bot added the cla: yes label Oct 11, 2021
@pullapprove pullapprove bot requested a review from atscott October 11, 2021 22:10
@atscott atscott added area: router feature Issue that requests a new feature target: minor This PR is targeted for the next minor release labels Oct 12, 2021
@ngbot ngbot bot added this to the Backlog milestone Oct 12, 2021
Copy link
Contributor

@atscott atscott left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just one nit on a misspelled variable. Thanks for the addition!

@atscott atscott added the action: presubmit The PR is in need of a google3 presubmit label Oct 12, 2021
@atscott
Copy link
Contributor

atscott commented Oct 12, 2021

presubmit

@atscott atscott added breaking changes target: major This PR is targeted for the next major release and removed action: presubmit The PR is in need of a google3 presubmit labels Oct 14, 2021
@atscott atscott modified the milestones: Backlog, v14-candidates Oct 14, 2021
@daiscog daiscog force-pushed the create-url-tree-relative-to-route-snapshot branch from b03608d to 266bea0 Compare October 15, 2021 13:31
Copy link
Contributor

@jessicajaniuk jessicajaniuk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🍪

This looks good aside from a typo in a variable name.

reviewed-for: public-api

…nk resolution in Router.createUrlTree

The relativeTo property of the navigationExtras parameter in the createUrlTree method of the Router class may now be an ActivatedRoute or an ActivatedRouteSnapshot.
The latter is useful in CanActivate route guards when building an alternative UrlTree to navigate to, relative to the URL that the current navigation is attempting to access.

BREAKING CHANGE: The relativeTo property of the UrlCreationOptions interface in the router package may now also be an ActivatedRouteSnapshot.

The relativeTo property is now typed `ActivatedRoute | ActivatedRouteSnapshot | null`.
Code accessing relativeTo may have to account for the possiblity this property is an ActivatedRouteSnapshot.

Fixes angular#22763
@daiscog daiscog force-pushed the create-url-tree-relative-to-route-snapshot branch from 266bea0 to 6b1c7ef Compare October 19, 2021 10:59
@atscott
Copy link
Contributor

atscott commented Oct 28, 2021

@daiscog Can you write a few tests that actually verify the creation behavior in a guard? The createUrlTree code is kind of bonkers in the way it constructs a URL because it depends on the ActivatedRoute being created from some part of the Router's currentUrlTree so that it can locate a UrlSegmentGroup to replace.
I've got a feeling that this actually still won't work in a guard because the ActivatedRouteSnapshot is created from the pending navigation so you can't use it to replace a part of the UrlTree that is the currentUrlTree of the Router.

@jessicajaniuk jessicajaniuk removed their request for review October 28, 2021 22:19
@pullapprove pullapprove bot requested a review from IgorMinar October 28, 2021 22:19
@daiscog
Copy link
Author

daiscog commented Oct 29, 2021

@atscott The point is not to replace part of the current UrlTree, but rather to replace the entire current UrlTree with an absolute path derived from resolving a relative URL against the pending navigation.

A simple, contrived example:

Navigating from /foo/bar/baz
Navigating to /at/some/other/place

Guard for the latter wants to redirect to /at/some/new/place but doesn't know the full prefix, so wants to resolve the URL relative to the pending navigation (i.e., ../../new/place).

If you still think it is necessary, I will take the time to try to codify these expectations in some tests?

@atscott
Copy link
Contributor

atscott commented Oct 29, 2021

@daiscog Yes, I understand what you're saying, but that's not how the code in createUrlTree works. The logic works as follows:

  1. Using the number of ../ in the commands, find correct UrlSegmentGroup/UrlSegment to modify in the ActivatedRoute that is the relativeTo
  2. Match that UrlSegmentGroup to the corresponding UrlSegmentGroup in the Router's currentUrlTree and replace it with a new group, created from the given commands

As I said before, because the ActivatedRouteSnapshot of the in-flight navigation was created at a different time, it will not be able to do the matching in (2) above, so this relative navigation will not work.

Copy link
Contributor

@atscott atscott left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting my review to request changes to add test cases. From my recent investigations in this area, I unfortunately don't think this will actually achieve the intended goal.

An alternative could be to expose a standalone method that creates a UrlTree from an ActivatedRoute/ActivatedRouteSnapshot without the urlTree: UrlTree parameter that's in this function. This should be possible but would require quite a bit of work and testing.

@daiscog
Copy link
Author

daiscog commented Nov 3, 2021

Hi @atscott

No problem, thanks for the extra info. I'll see if I can get time to work some more on this at the weekend.

Cheers,

Dai

@pullapprove pullapprove bot removed the request for review from IgorMinar December 1, 2021 17:57
@atscott
Copy link
Contributor

atscott commented Feb 10, 2022

Closing due to #43800 (comment). I don't believe this will actually work based on how the code is structured now. Feel free to open a new PR if you have a test that proves me wrong.

@atscott atscott closed this Feb 10, 2022
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Mar 13, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: router breaking changes cla: yes feature Issue that requests a new feature target: major This PR is targeted for the next major release target: minor This PR is targeted for the next minor release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

bug: relative navigation doesn't work inside route guards
3 participants