expenguin
expenguin

Reputation: 1124

Subscription pipe logic errantly processing when using switchMap on button press

Edit: I have found a workaround by using updating my event filter to:

filter(event => 
    event.type === EventType.NavigationEnd && 
    this.route.snapshot.queryParams['test'])

which solves getting the params for my issue, however the question remains about the errant behavior of switchMap inside pipe(), so the issue remains open.


I have the following subscription to Angular's routing events in a service:

constructor(
    private route: ActivatedRoute,
    private router: Router
) {
    this.router.events.pipe(
        // Filter events to NavigationEnd only
        filter(event => {
            console.log(event);
            return event instanceof NavigationEnd;
        }),

        // Get all query params
        switchMap(() => this.route.queryParams)
    ).subscribe(params => {
        console.log("ENTERED");
        console.log(params);
    });
}

The service is pulled into my main app component via the constructor to allow this to trigger anywhere in my app:

public constructor(
    private testService: TestService
) { }

I expect it to filter all router events that don't match NavigationEnd and only log params when the NavigationEnd event is detected.

When navigating to the url via my browser address bar, I successfully see that the only router events I see my logs under is the NavigationEnd event:

Params are successfully logged under NavigationEnd

Moving to implementation, I created a button that will add a query parameter when clicked to the URL:

<button (click)="addTestToRoute()">Click me to add test to route</button>

Which has the following component method:

public addTestToRoute(): void {
    let newParams = { test: "12345" };

    this.router.navigate(
        [],
        {
            queryParams: newParams,
            queryParamsHandling: 'merge'
        });
}

When clicking this button, the values are errantly logged under GuardsCheckEnd, but also logged under NavigationEnd. I am confused as to why this is, as any logic I apply to try and control the flow of the pipe logic is not adhered to and the log is ALWAYS displayed under GuardsCheckEnd. To note, I have no routing guards in place:

Params are logged under both GuardsCheckEnd and NavigationEnd

Any help towards understanding why this is happening would be greatly appreciated.

Upvotes: 0

Views: 59

Answers (1)

Dan Peresenchuk
Dan Peresenchuk

Reputation: 82

It happens because you switched stream to this.route.queryParams observable. Here is the general idea:

  1. During the first navigation cycle events are filtered up until NavigationEnd event. switchMap switches stream to this.route.queryParams as a source.
  2. New navigation cycle starts after button click, in a meantime ActivatedRoute emits route params as well.
  3. Subscription receives emitted value --> this is the point where your first ENTERED message appears around GuardsCheckEnd
  4. NavigationEnd is fired and invalidates previous subscription. --> second ENTERED

Not sure about the details, but most likely, queryParams emits new param values at the end or right after GuardsCheckEnd.

Upvotes: 0

Related Questions