Search code examples
angularrxjssubjectbehaviorsubject

Rxjs Subject.asObservable() not working but BehaviorSubject works...why?


I have checked out this https://github.com/angular/angular/issues/12129 but I don't see any solution...

Angular 2.0.1 AsyncPipe doesn't work with Rx Subject .

The solution here is to create an observable variable in the component

Which I have but still not working... not sure why its not working if I switch Subject in my UserStateService to BehaviorSubject everything works...

Note: Both UserDataService and UsersStateService is provided at the root app.module.ts.

user-data.service.ts -> make http request which I call in my component

fetchUsers():void{
   this.httpClient.get<User[]>(this.apiUrl, {
  observe: 'body',
  responseType: 'json'
})
.subscribe( (response: User[])=>{
    this.usersStateService.setUsersList(response);  <-- set to local state service

  });

}

users-state.service.ts

userListState = new Subject<User[]>();   <-- Change this to BehaviorSubject<User[]>([])  everything works!

setUsersList(users: User[]):void {
  this.userListState.next(users.slice());
}

getUsersListState():Observable<User[]>{
   return this.userListState.asObservable();
}

component.ts

 users: Observable<User[]>;

 ngOnInit() {

 if(this.usersStateService.hasUserList()){

  this.users = this.usersStateService.getUsersListState();  -|
                                                             |
  // this.usersStateService.getUsersListState()              |
  //   .subscribe((x) => console.log(x));                   -| <-- This does not output for some reason IF Subject... BehaviorSubject works..
}else{
  console.log("No data in local stat -> fetch") . <-- This works either with Subject or BehaviorSubject
  this.userData.fetchUsers();
  this.users = this.usersStateService.getUsersListState();
}

}

HTML

<li *ngFor="let u of (users | async)">u.name</li>

Please any insights will be great thank you!!


Solution

  • Subject does not hold any data, its just invoke anything that subscribe to it with the value. BehaviorSubject holds data and everytimes you call emit it is replacing the current data.

    When you are trying to console log from your service the UserList:
    With Subject it does not contain any persistent data.

    this.usersStateService.getUsersListState()              
     .subscribe((x) => console.log(x));  ==> would be empty 
    

    With BehaviorSubject it holds the last data, and also can be initialized with values.

    let _array = ['one','two']
    let bs = new BehaviorSubject<any>(_array ).asObservable();
    bs.subscribe(arr => {
     console.log(arr) // ==> Would log the _array: ['one','two']
    })
    

    So in your case, when you trying to get the data via Subject, it just doesnt exists after the first invoke (when you emit), while BehaviorSubject holds your initial value, and each time you emit, so theres always persistent data.
    **If you need more than one value each time, you should look into ReplySubject