Improved Navigation in Angular 7 with switchMap
In this article we’ll examine these changes and see how they can be used. We’ll also see how switchMap enforces that only one navigation can exist at any one time.

Improved Navigation in Angular 7 with switchMap
In this article we’ll examine these changes and see how they can be used. We’ll also see how switchMap enforces that only one navigation can exist at any one time.


With PR #25740 all navigations performed by Angular’s router are merged into a single, observable stream. There can also be only one active navigation at any time. This provides the benefits of making navigations faster and more predictable. Although these changes are mostly internal, they do affect how we should think about navigations and routing in our applications.
This is a major refactor of how the router previously worked. There are a couple of major advantages to this refactor and the future work will be built on top of it.
These changes were released as part of Angular 7.0. In this article we’ll examine these changes and see how they can be used. We’ll also see how switchMap enforces that only one navigation can exist at any one time.
Understanding NavigationLink to this section
A navigation happens whenever the URL changes. This can be the result of some imperative action (a service calling navigate
, or a guard returning a UrlTree) or some other action such as a user clicking on a [routerLink]
directive.
Once a navigation starts, it runs through the following stages:
- Process redirects
- URL to path matching
- Run guards and resolvers
- Render components and update the browser location
If you’d like to know more, I’ve written an article explaining each stage.
The ProblemLink to this section
Before #25740, it was possible for multiple navigations to run at once. As you can imagine, this could cause problems.
Consider the following scenario:
- A user clicks on link X. A new navigation with an id of 1 starts.
- During the navigation to X, guards and resolvers run asynchronously, and take 10 seconds to complete.
- During those 10 seconds, the user gets fed up, and clicks on link Y, which starts a new navigation to Y, with id of 2.
- Navigation 2 must wait on navigation 1’s guards and resolvers to finish (the results of which will be ignored).
- Maybe one of the guards in navigation 1 fails and initiates a redirect while navigation 2 is waiting. It’s now difficult to tell where the user will land.
Jason Aden discussed this exact problem in his talk at AngularConnect 2018, which I recommend checking out.
In short, managing simultaneous navigations was messy, both inside and outside of the framework. With the changes introduced in 25740, there can be only one active navigation at any one time.
As we’ll see, this simplifies matters and makes navigation easier to reason about.
The ChangesLink to this section
The biggest internal changes in 25740 are as follows:
- Each stage of the navigation cycle is now represented by its own operator (redirects, route recognize, etc)
- These operators are run through a switchMap which ensures that only the most recent navigation is considered. And, it will cancel and clean up any pending navigations.
The DetailsLink to this section
One map can make all the difference
As mentioned previously, the new “one navigation at a time” rule is enforced by the mighty switchMap
operator. By creating a single observable stream and pipelining all navigations in the router through switchMap
instead of a mergeMap
any new navigation will cause the previous navigation to be cancelled and cleaned up by switchMap
.
RefactorswitchMap
instead of the previousmergeMap
to ensure new navigations cause a cancellation and clean up of already running navigations
- excerpt from PR 25740
If you aren’t already aware of how powerful switchMap is, or how it works, I recommend checking out Nicholas Jamieson’s article on the topic.
Custom operatorsLink to this section
Starting with 25740, different parts of the navigation process have been refactored into custom operators, which live under /packages/router/src/
operators. You can see that each of the navigation stages mentioned previously are now represented by operators:
- apply_redirects.ts
- recognize.ts
- check_guards.ts and resolve_data.ts
- activate_routes.ts
Internally, transitions between navigations are represented by the NavigationTransition
type. An observable of NavigationTransition
called router.transitions
is used with the main router.navigations
observable to handle new navigation. This is where switchMap
is being used to cancel any current navigations whenever a new navigation happens.
<>Copyprivate setupNavigations(transitions: Observable<NavigationTransition>): Observable<NavigationTransition> { return transitions.pipe( filter(t => t.id !== 0), // Extract URL map(t => ({...t, extractedUrl: this.urlHandlingStrategy.extract(t.rawUrl)}) as NavigationTransition), // Using switchMap so we cancel executing navigations when a new one comes in switchMap(t => {
You can see the entire pipeline if you check out setupNavigations
in router.ts
.
BenefitsLink to this section
With these new changes, any new navigation will automatically cancel and cleanup any pending navigations. This means fewer memory leaks and less time spent waiting for guards and resolvers to finish running for a stale navigation. In larger applications these benefits can really make a difference.
Fortunately, all of these changes are internal. So there isn’t really anything you need to change in your applications. Just be aware that you can have only one active navigation at a time.
SummaryLink to this section
With the changes in 25740:
- There is only one active navigation at any time.
- When a new navigation is triggered, any pending navigation is cancelled and cleaned up.
- Internally, each stage of the navigation cycle has been broken up into separate operators.
- These changes should provide faster, more reliable navigation.
Happy navigating!
Comments (0)
Be the first to leave a comment
About the author

Fullstack Developer. Love digging into the internals of stuff. Always trying to reach the next level.

About the author
Nate Lapinski
Fullstack Developer. Love digging into the internals of stuff. Always trying to reach the next level.
About the author

Fullstack Developer. Love digging into the internals of stuff. Always trying to reach the next level.