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
fix(router): empty resolvers cancel navigation #24621
Conversation
@jasonaden Hey! Please, is there any chance to get this merged when I fix these merge conflicts? |
Hey, any update on this? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One small nit but otherwise LGTM. Could you rebase this PR to the current master so we can run tests?
8dea202
to
4347a6a
Compare
e6a9ec5
to
9b1dd2e
Compare
@atscott I finally rebased this PR. I had to make some refactoring because Angular Router has changed a lot in the meantime. I was was battling with bundle size of one integration test because I originally solved this by adding So finally this should be good to go. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, thanks for adding this fix! I ran a subset of the internal presubmits yesterday and they appeared to be passing. I'll need to run them all tonight just to be safe, but I think this should be pretty much good to go.
return from(canActivateChecks) | ||
.pipe( | ||
concatMap( | ||
check => runResolve( | ||
check.route, targetSnapshot !, paramsInheritanceStrategy, moduleInjector)), | ||
reduce((_: any, __: any) => _), map(_ => t)); | ||
takeLast(1), map(_ => t), ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great catch here. Really weird way to have been using reduce before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it took me a while to figure out why is it even used there :).
@@ -1629,6 +1630,64 @@ describe('Integration', () => { | |||
expect(e).toEqual(null); | |||
}))); | |||
|
|||
it('should not navigate when all resolvers return empty result', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great tests. Thanks for adding these.
global presubmits appear to show some failures as a result of this CL. I'll have to investigate what's going on there. |
I added at least a few unit tests for I'm suspicious that right now |
I was finally able to run integration tests. With |
Oh, good. You identified the internal test failure before I got a chance to tell you about it :)
Hmmm, that does seem suspicious. That wasn't how it was working before, was it?
Yea, the bundle size tests frequently need to be updated. |
Hi @martinsik, I want to clarify what the current behavior is for resolvers returning
This behavior can be confirmed by patching your two tests into master and running them. I think we can agree that the inconsistency is not desirable. Making this consistent, either by having both cases cancel navigation as is done in this PR or by allowing navigation to complete in both cases, is probably considered a breaking change because there could be applications that rely on the current behavior (knowingly or otherwise). I've come across several cases internally where there were An argument could also be made for fixing this in a way which allows navigation to complete in all cases rather than cancelling it, though I'm on your side of the discussion there -- if a developer really wanted Lastly, this behavior is worth documenting. Can you find an appropriate place in the router documentation on resolvers to add a note? |
c9fa018
to
1de4ab2
Compare
@atscott Rebased and resolved. |
Hi @martinsik, I've been working through more test failures that came out of this change and realized that this needs to be marked as a breaking change. Please add a note about this at the end of your commit message. Also, please expand upon the description in the commit body so readers can quickly understand what's being changed and why. Finally, please add a note (and maybe even a test) that this will affect any resolvers used in
The commit message should be something like
|
@martinsik - friendly ping to update the commit message, as mentioned in the last comment. Since this is a breaking change, we'll need to get it into a major release. If we miss v10, it will need to wait for v11. |
a1f20e0
to
36c7de3
Compare
…ith no "next" emission This change aligns behavior for resolvers which return EMPTY. Currently EMPTY resolvers have inconsistent behavior: - One resolver that returns EMPTY => won't navigate and just ends on ResolveStart router event. - Two resolvers where both return EMPTY => throws "Error: Uncaught (in promise): EmptyError: no elements in sequence" - Two resolvers where one returns a value and the other one returns EMPTY => Navigates successfully. With this change any EMPTY resolver will cancel navigation. BREAKING CHANGE: Any resolver which return EMPTY will cancel navigation. If you want to allow the navigation to continue, you will need to update the resolvers to emit some value, (i.e. defaultIfEmpty(...), of(...), etc). PR Close angular#24195
@atscott I updated the commit message and added two more tests using |
latest global presubmit - both failures are already failing at head. |
caretaker note: Please merge and sync this one separately from others if possible. |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
…ith no "next" emission (angular#24621) This change aligns behavior for resolvers which return EMPTY. Currently EMPTY resolvers have inconsistent behavior: - One resolver that returns EMPTY => won't navigate and just ends on ResolveStart router event. - Two resolvers where both return EMPTY => throws "Error: Uncaught (in promise): EmptyError: no elements in sequence" - Two resolvers where one returns a value and the other one returns EMPTY => Navigates successfully. With this change any EMPTY resolver will cancel navigation. BREAKING CHANGE: Any resolver which return EMPTY will cancel navigation. If you want to allow the navigation to continue, you will need to update the resolvers to emit some value, (i.e. defaultIfEmpty(...), of(...), etc). PR Close angular#24195 PR Close angular#24621
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
When a route has at least two resolvers (Observables) and both of them
complete
without anynext
item thelast()
operator throws an exception.Issue Number: #24195
What is the new behavior?
When there's at least one empty resolver then navigation is canceled.
I think there are two ways this could work. When at least one resolver is empty or when all resolvers are empty. The original issue #24195 mentions the first option and it probably makes more sense because if I'm fine with one of the resolvers producing an empty response I can handle it in the resolver with eg.
defaultIfEmpty
operator.Does this PR introduce a breaking change?
This shouldn't be a breaking change because it's very unlikely that anybody was relying on the previous behavior.Other information
I actually made this more simple because I used only
forkJoin
andmap
operators with singlepipe()
call.I didn't want to update docs until I have approval from somebody competent that these changes make sense.