Search code examples
rxjsangular2-observablesbehaviorsubject

RxJs Observable duplicate values


So i have pretty straight forward scenario. One subject and observable. When client logs in i publish success, when user logs out i publish false.

Problem is in subscribe method in LoginComponent First time everything works great. User logs in i get one event, but after that when user logs out second time and logs in again i get 2 same events, again if user logs out and then logs in i get 3 duplicate events and so on.

AuthService.ts

public _loggedIn: Subject<LoggedInOrResetPassword> = new Subject();
public loggedId: Observable<LoggedInOrResetPassword> = this._loggedIn.asObservable();


obtainAccessToken(){
 // ommitted
 this.httpClient.post(environment.baseUrl + url, null, requestOptions)
                .subscribe(data => {
                  this.saveToken(data);
                  this._loggedIn.next(LoggedInOrResetPassword.createTrue());
                });
  // ommitted
}


private logout(navigateTo?: string){
    this._loggedIn.next(LoggedInOrResetPassword.createFalse());
}

LoginComponent.ts

ngOnInit() {
    this.authservice.loggedId.subscribe( ( loggedInOrResetPassword: LoggedInOrResetPassword ) => {
    // HERE I GET DUPLICATE VALUES
});

Solution

  • The reason is that you are NOT unsubscribing when LoginComponent is destroyed.

    Your code should be changed as follows

    First add an instance property to LoginComponent to store the subscription, such as

    export class LoginComponent implements OnInit, OnDestroy {
      .....
      loginSubscription: Subscription;
      .....
    }
    

    Then change ngOnInit so that you store the subscription in the newly added property

    ngOnInit() {
        this.loginSubscription = this.authservice.loggedId.subscribe( ( loggedInOrResetPassword: LoggedInOrResetPassword ) => {
        // HERE I GET DUPLICATE VALUES
    });
    

    Eventually add ngOnDestroy to make sure you unsubscribe when the component gets destroyed

    ngOnDestroy {
      if (this.loginSubscription) {
        this.loginSubscription.unsubscribe();
      }
    }
    

    Take a look at the async pipe of Angular as an alternative method to subscribe to Observables and automatically unsubscribe.