Angular2 Query Params Subscription Fires Twice

Router observables (as another answer mentions) are BehaviorSubject subjects, they differ from regular RxJS Subject or Angular 2 EventEmitter in that they have the initial value pushed to the sequence (an empty object in the case of queryParams).

Generally the possibility of subscribing with initialization logic is desirable.

The initial value can be skipped with skip operator.

this._route.queryParams
.skip(1)
.subscribe(params => ...);

But more natural way to handle this is to filter out all irrelevant params (initial params falls into this category). Duplicate authorization_code values can also be filtered with distinctUntilChanged operator to avoid unnecessary calls to the backend.

this._route.queryParams
.filter(params => 'authorization_code' in params)
.map(params => params.authorization_code)
.distinctUntilChanged()
.subscribe(authCode => ...);

Notice that Angular 2 imports a limited amount of RxJS operators (at least map in the case of @angular/router). If full rxjs/Rx bundle isn't used, it may be necessary to import extra operators (filter, distinctUntilChanged) that are in use with import 'rxjs/add/operator/<operator_name>'.


The best way to overcome this was subscribing router events, and processing query params only after the route is ticked to navigated state:

  public doSomethingWithQueryParams(): Observable<any> {
      let observer: Observer<any>;
      const observable = new Observable(obs => observer = obs);

      this.router.events.subscribe(evt => {
        // this is an injected Router instance
        if (this.router.navigated) {
          Observable.from(this.activatedRoute.queryParams)
            // some more processing here
            .subscribe(json => {
              observer.next(json);
              observer.complete();
            });
        }
      });
      return observable;
  }