Skip to content
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

10.1.0 Router empty path regression #38691

Closed
akturatech opened this issue Sep 3, 2020 · 22 comments
Closed

10.1.0 Router empty path regression #38691

akturatech opened this issue Sep 3, 2020 · 22 comments
Milestone

Comments

@akturatech
Copy link

🐞 bug report

Summary

Upgrading to Angular 10.1.0 does not stop routing on the first matching route entry.

Is this a regression?

Yes, this used to work in all previous versions of Angular (from v2 onwards).

Description

Previous versions of Angular allowed routes to be defined in a prioritized order. As per the screenshot below, we direct the route to specific module if a path is provided, however if no path is provided, we route to the main application module.

image

It appears that V10.1.0 now triggers the last path (the one highlighted in the screenshot above) even if the other paths load first. In our case, if we try to login via the auth path, it first shows the login page for a brief few milliseconds and then it tries to navigate to the main module via the path: '' entry but this fails the auth check and redirects back to the auth module and this cycle then repeats forever.

🔬 Minimal Reproduction

Removing the highlighted line in the above screenshot stops the repeated loading from occurring. But this isn't a fix as it stops our app from working as well.

🌍 Your Environment

Angular Version:


Angular CLI: 10.1.0
Node: 12.10.0
OS: linux x64

Angular: 10.1.0
... animations, cli, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router
Ivy Workspace: Yes

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.1000.7
@angular-devkit/build-angular     0.1001.0
@angular-devkit/build-optimizer   0.1001.0
@angular-devkit/build-webpack     0.1001.0
@angular-devkit/core              10.0.7
@angular-devkit/schematics        10.1.0
@angular/cdk                      10.1.3
@ngtools/webpack                  10.1.0
@schematics/angular               10.1.0
@schematics/update                0.1001.0
rxjs                              6.6.2
typescript                        3.9.7
webpack                           4.44.1

@indraraj26
Copy link

indraraj26 commented Sep 3, 2020

i think you will have to add pathMatch:"full" in you blank path:""

@ngbot ngbot bot added this to the needsTriage milestone Sep 3, 2020
@akturatech
Copy link
Author

Good morning @indraraj26 . Thank you for your suggestion.

I tested this and unfortunately it doesn't work. The reason is that the last route redirects to our main module which has many routes of its own. With a full match, the routes within the main module no longer work.

Hopefully this explains our routing system (which was implemented when the first version of angular was released with lazy loaded modules and has worked until now):

/ : app module. has shared libraries for parent modules (auth, main etc)
  /auth : auth module allows login, signup etc. auth modules has its own lazy loaded modules
  / : main module. has guard to stop access. redirects to auth if not logged in. has shared libraries for main modules
    request : example lazy loaded page. this has its own modules as well
    calendar : another example lazy loaded page
    ...

Some examples paths are:

/ : will try to access main module which will redirect to requests module if logged in. if not, will redirect to auth module to log in
/auth/sign-in 
/requests/edit : will work only if signed in
/calendar : will work only if signed in

@akturatech
Copy link
Author

akturatech commented Sep 3, 2020

OK I tried changing the path to '**' instead of empty and this actually gets me a little bit further - it now loads the main module but doesn't load any of the children in the main module.

My main module has routes like this:
image

I'm guessing here that '**' in the app route is consuming the entire path and therefore only the path:'' at the top of the main route is matching.

The only way i can get the new version of Angular to work is to provide the main module with a path name like this:
image

But this is not an option for me as our app is used by our users to build forms and each form has a path that is included in an email that our users send to our clients. Changing our path to these forms is not an option as it will disrupt several hundred users as the previous form paths will no longer be valid.

@indraraj26
Copy link

indraraj26 commented Sep 4, 2020

Hi @akturatech ,

Do you have router-outlet in MainComponent.html it is needed so that children can render, as you are not using component-less routing.

Also is it possible for you to provide reproduction via stackblitz ?

@akturatech
Copy link
Author

akturatech commented Sep 4, 2020

Hi @indraraj26,

Do you have router-outlet in MainComponent.html

Yes i do.

Also is it possible for you to provide reproduction via stackblitz

Yes sure...

Example project is here in v10.0.9. It works: https://stackblitz.com/edit/angular-ivy-crjaz8?file=src%2Fapp%2Fguard%2Fa.guard.ts
If you upgrade to v10.1.0 it blows up.

The reason is that the guard on the empty path in the app module is running when it shouldn't be. It should run only when the path: '' is activated, but it runs even if we go to '/auth' path. This is only happening in 10.1.0 and not in older versions.

Note that the empty path is not activating as it is not printing "main works!". I believe routing is working as it should. It appears that canLoad guard though is incorrectly firing.

In my main app, we use the guard on the empty path to check that the user is authorised and redirect back to the 'auth' path if they are not. In v10.1, as the guard is now firing even when we go to 'auth' path, it is failing auth check and returning false and redirecting back to auth path, which causes the guard to check again and repeat forever.

@akturatech
Copy link
Author

akturatech commented Sep 4, 2020

One more clue - if i name the empty path (eg path: 'main') then the guard works correctly and runs only when the 'main' path is activated. So the issue is:
canLoad on an empty path is running the guard even if the path is not being loaded.

@AlexanderOpran
Copy link

We have the exact same issue as described by @akturatech. Any updates regarding this?

@akturatech
Copy link
Author

@AlexanderOpran No. This issue seems to haven fallen through the cracks.

@indraraj26 Do you know how I can raise this with the angular team as we've had no response yet. Should I re-raise the issue again?

@akturatech
Copy link
Author

@AlexanderOpran I wonder if it is worth you raising this as your own issue and linking back to this one or including my stackblizt replicating the issue? All the newer bugs seem to be getting assigned to people and have confirmed tags etc. This one seems to have been lost.

@atscott atscott added freq2: medium router: config matching/activation/validation router: lazy loading regression Indicates than the issue relates to something that worked in a previous version type: bug/fix labels Sep 9, 2020
@ngbot ngbot bot modified the milestones: needsTriage, Backlog Sep 9, 2020
@atscott
Copy link
Contributor

atscott commented Sep 9, 2020

Likely caused by d7dd295 which should be reverted.

@atscott
Copy link
Contributor

atscott commented Sep 9, 2020

Note that as a temporary workaround, you can use
return this.router.createUrlTree(['auth']);
instead of

this.router.navigate(['auth']);
return false;

because the PR was meant to respect the ordering with prioritization, but only works with returning UrlTrees and fails to do so if a guard calls router.navigate to "redirect" which cancels the current navigation immediately and proceeds with the new one.

@akturatech
Copy link
Author

@atscott Thank you for the update and workaround :)

atscott added a commit to atscott/angular that referenced this issue Sep 9, 2020
…f needed

There is a slight difference between `map`...`concatAll` and `concatMap`
in that the latter (`concatMap`) will ensure that the computations are
executed in-order and only if needed while the former may execute the
`map` body of all items if they do not emit immediately. That is, if the stream
is
`from([a, b, c]).pipe(map(v => of(v).pipe(delay(1))), concatAll(), first())`
the `map` body will execute for all of `a`, `b`, and `c`.
However, the following will only execute the `concatMap` body for `a`
`from([a, b, c]).pipe(concatMap(v => of(v).pipe(delay(1))), first())`

See https://stackblitz.com/edit/rxjs-cvwxyx

fixes angular#38691
@atscott
Copy link
Contributor

atscott commented Sep 9, 2020

@akturatech I have a fix for this out for review and it should make it into the 10.1.2 release next week. If you want the fix now, it actually happens to already be fixed in 11.0.0-next.1.

@emillime
Copy link

emillime commented Sep 10, 2020

Note that as a temporary workaround, you can use
return this.router.createUrlTree(['auth']);
instead of

this.router.navigate(['auth']);
return false;

because the PR was meant to respect the ordering with prioritization, but only works with returning UrlTrees and fails to do so if a guard calls router.navigate to "redirect" which cancels the current navigation immediately and proceeds with the new one.

I have the same issue, thank you for the workaround!
But what do we return as UrlTree in the case where it returned true before?

Edit:
Nevermind, I saw in the documentation that the type of CanLoad is boolean | UrlTree so we can still return true.
This seems like a better solution than using router.navigate. Thank you!

AndrewKushnir pushed a commit that referenced this issue Sep 10, 2020
…f needed (#38780)

There is a slight difference between `map`...`concatAll` and `concatMap`
in that the latter (`concatMap`) will ensure that the computations are
executed in-order and only if needed while the former may execute the
`map` body of all items if they do not emit immediately. That is, if the stream
is
`from([a, b, c]).pipe(map(v => of(v).pipe(delay(1))), concatAll(), first())`
the `map` body will execute for all of `a`, `b`, and `c`.
However, the following will only execute the `concatMap` body for `a`
`from([a, b, c]).pipe(concatMap(v => of(v).pipe(delay(1))), first())`

See https://stackblitz.com/edit/rxjs-cvwxyx

fixes #38691

PR Close #38780
@atscott
Copy link
Contributor

atscott commented Sep 10, 2020

Fixed in 9c51ba3

@atscott atscott closed this as completed Sep 10, 2020
@akturatech
Copy link
Author

That is awesome @atscott . Thank you so much.
Love Angular and love the team as well. Such a great framework.

@akturatech
Copy link
Author

@atscott Thank you for the workaround suggestion. I finally got to test it. Unfortunately setting UrlTree doesn't work for us as the guard redirects to a different subdomain on authentication failure (or app has a subdomain per user and a root subdomain for login) and therefore we cannot use UrlTree.
I'll report back when 10.1.2 is released and let you know if the fix works.

@AlexanderOpran
Copy link

Issue still persists even with 10.1.2

@atscott
Copy link
Contributor

atscott commented Sep 17, 2020

Hi @AlexanderOpran, could you provide a reproduction? The stackblitz for this report does work with 10.1.2: https://stackblitz.com/edit/angular-ivy-sez7kw?file=src%2Fapp%2Fapp.component.ts

@akturatech
Copy link
Author

Good morning @atscott. I can confirm my project now works perfectly with 10.1.2. Thank you!!

@AlexanderOpran
Copy link

AlexanderOpran commented Sep 18, 2020

@atscott I will try and do a stackblitz to reproduce this. Perhaps another related issue but router.navigate does not seem to work from inside guards. It will trigger the module guard infinitely even if the page/module I try to navigate to is not protected by any. This is also happening only with the ** path, not the named ones.

@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 Oct 19, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants
@sonukapoor @atscott @emillime @AlexanderOpran @indraraj26 and others