You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Redirect within Resolve from Angular to AngularJS router breaks in some cases #17023
We’ve got a situation where in a Resolver, users may want to redirect to an AngularJS route (or any URL not handled by the Angular router). This works okay when you first click on the route as it falls into an else if clause in executeScheduledNavigation designed to clean up the currently rendered route. runNavigate is then run and AngularJS router ends up taking over.
But if you cmd+click (or deep link) to this same route, you end up going to / route every time, assuming Angular Router is not set up to handle the / route. This happens because / is the default rawUrlTree when router is instantiated, and Angular Router won’t know about this route.
Here's an example reproducing the issue. If you click on Settings and then Page Size Settings, you will be redirected to /messages/inbox. But if you cmd+click you will be redirected to /.
As it turns out, adding "/" to the conditions of UrlHandlingStrategy.shouldProcessUrl will make the above scenario work.
What's happening on clicking a link that's redirected in a resolve is the router sees the new URL being linked to and finds it doesn't handle that URL. It looks and sees that the previous URL was handled by the Angular router so it goes into "cleanup" mode. It then lets that URL through and it gets handled by the AngularJS router.
In direct-link mode, the Angular router sees it doesn't handle the link and looks for the previously successfully rendered route. There isn't one so it defaults to root (or /). It also finds it doesn't handle this route so redirects to /.
Therefore, adding / to the list of URLs handled by the Angular router will trick Angular router into going down the "working" code path.
However, this is not a perfect solution as the history managed by the Angular router is incorrect (note that browser history is correct, so browser back buttons work as intended). The Angular router history ends up with a navigation to / in both cases, meaning a link such as <a routerLink="../">Back</a> will always land back at /.
An implementation of the above can be found here. Note there is a new directory on this branch called empty with an empty route configured. This was an attempt to address this problem using a "sink route" as per the description in this article, but this did not seem to address the problem.
A possibility would be to let the Angular Router handle the initial page that was loaded. In other words, right now we have an issue because we are routing to an ng2 route, then in a Guard we are redirecting to an ng1 route. The router tries to "clean up" and looks to see the last successful navigation. Because we are deep linking, there isn't one and the default is used (/).
What if the default were the route first routed to. Or maybe don't have a default and don't do this cleanup step if there's no default.
Needs to be tested. Noting here to track possible solutions.
Further review seems to indicate that redirecting from an ng2 route to another ng2 route doesn't work. The router falls into the same if condition mentioned above, but on redirect tries to just re-navigate. State seems to get messed up in this case and the redirect fails (and user lands on / root page).
Note that there's another difference between the ng2 and ng1 version of the redirect. When redirecting from ng2 to ng1 after previously successfully rendering an ng2 route, the redirect will work. When redirecting from ng2 to ng2 route after previously successfully rendering an ng2 route, the redirect will fail and will go back to the last successfully rendered ng2 route.
Both instances above will redirect to root on a deep link.
A part of the fix here should be to add the ability to cancel the current navigation. This should "rollback" to a default-like state, then start the new navigation (if redirecting).
Closing, as this seems to have been fixed at some point. I update to the latest versions of both AngularJS and Angular, and followed the steps to reproduce:
If you click on Settings and then Page Size Settings, you will be redirected to /messages/inbox. But if you cmd+click you will be redirected to /.
Activity
jasonaden commentedon May 31, 2017
As it turns out, adding "/" to the conditions of
UrlHandlingStrategy.shouldProcessUrlwill make the above scenario work.What's happening on clicking a link that's redirected in a resolve is the router sees the new URL being linked to and finds it doesn't handle that URL. It looks and sees that the previous URL was handled by the Angular router so it goes into "cleanup" mode. It then lets that URL through and it gets handled by the AngularJS router.
In direct-link mode, the Angular router sees it doesn't handle the link and looks for the previously successfully rendered route. There isn't one so it defaults to root (or
/). It also finds it doesn't handle this route so redirects to/.Therefore, adding
/to the list of URLs handled by the Angular router will trick Angular router into going down the "working" code path.However, this is not a perfect solution as the history managed by the Angular router is incorrect (note that browser history is correct, so browser back buttons work as intended). The Angular router history ends up with a navigation to
/in both cases, meaning a link such as<a routerLink="../">Back</a>will always land back at/.jasonaden commentedon May 31, 2017
An implementation of the above can be found here. Note there is a new directory on this branch called
emptywith an empty route configured. This was an attempt to address this problem using a "sink route" as per the description in this article, but this did not seem to address the problem.jasonaden commentedon Sep 15, 2017
A possibility would be to let the Angular Router handle the initial page that was loaded. In other words, right now we have an issue because we are routing to an ng2 route, then in a Guard we are redirecting to an ng1 route. The router tries to "clean up" and looks to see the last successful navigation. Because we are deep linking, there isn't one and the default is used (
/).What if the default were the route first routed to. Or maybe don't have a default and don't do this cleanup step if there's no default.
Needs to be tested. Noting here to track possible solutions.
jasonaden commentedon Sep 15, 2017
Further review seems to indicate that redirecting from an ng2 route to another ng2 route doesn't work. The router falls into the same
ifcondition mentioned above, but on redirect tries to just re-navigate. State seems to get messed up in this case and the redirect fails (and user lands on/root page).Note that there's another difference between the ng2 and ng1 version of the redirect. When redirecting from ng2 to ng1 after previously successfully rendering an ng2 route, the redirect will work. When redirecting from ng2 to ng2 route after previously successfully rendering an ng2 route, the redirect will fail and will go back to the last successfully rendered ng2 route.
Both instances above will redirect to root on a deep link.
jasonaden commentedon Sep 15, 2017
A part of the fix here should be to add the ability to
cancelthe current navigation. This should "rollback" to a default-like state, then start the new navigation (if redirecting).atscott commentedon Jul 14, 2020
Closing, as this seems to have been fixed at some point. I update to the latest versions of both AngularJS and Angular, and followed the steps to reproduce:
cmd+click navigated to
/messages/inboxhttps://github.com/atscott/angularbugrepros/tree/ng1ng2router_redirect_to_ng1
angular-automatic-lock-bot commentedon Aug 14, 2020
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.