0

I want to subscript to an observable that has a filtered value, but the filtering part isn't working.

In my service, I have

export class UserService {

  private userList: user[];
  public userList$ = new BehaviorSubject<user[]>([]);

  constructor() {
    this.userList = [
      {
        name : "ben",
        isActive : true,
      },
      {
        name : "chen",
        isActive : true,
      },
      {
        name : "Ray",
        isActive : true,
      },
      {
        name : "GuanJiaHong",
        isActive : true,
      },
      {
        name : "Maoge",
        isActive : true,
      },
    ]; 

    this.userList$.next(this.userList);
  }

  getActiveUsers(): Observable<user[]> {
    return this.userList$.asObservable().pipe(map(user => user.filter(x => x.isActive == true)));
  }

  setToInactive(user: user) {
    const currentUser = this.userList.find(x => x == user);
    if(currentUser != undefined) {
      currentUser.isActive = false;
    }
  }
}

and in my component, I have

export class ActiveUsersComponent implements OnInit {

  activeUser$: Observable<user[]> = new Observable();

  constructor(private userService: UserService) { }

  ngOnInit(): void {
    this.activeUser$ = this.userService.getActiveUsers();
  }

  setInactive(user: user) {
    this.userService.setToInactive(user);
  }

}

In my activeUser template, I have

Active User:<br>
<div *ngFor="let user of activeUser$ | async">
    {{user.name}} <button (click)="setInactive(user)">inactive</button><br>
</div>

when I set a user to inactive, this.activeUser$ should be filtered with only active user and the template should only be showing the active user, but it's still showing all the user including inactive user, I wonder what's wrong with my Observable implementation? Thank you.

Chen Long
  • 69
  • 6

1 Answers1

2

You forgot to publish the new state of your userList in the userList$ stream.

In other words in your setToInactive method after changing the currentUser attribute do:

this.userList$.next(this.userList);

Mubramaj
  • 641
  • 9
  • 14
  • Thank you, I'm having difficulting understanding how behaviorSubject and Observable works, shouldn't `this.userList$` always keeping track of the latest stateof `this.userList` and that's the purpose of using Observable and BehaviorSubject? – Chen Long Oct 07 '21 at 21:12
  • 1
    No, it will not automatically track the changes unless you explicitly push a new item into the stream. I think this post will help you understand Observable and Subject https://stackoverflow.com/questions/47537934/what-is-the-difference-between-observable-and-a-subject-in-rxjs then this one will help you understand the BehaviourSubject https://stackoverflow.com/questions/43348463/what-is-the-difference-between-subject-and-behaviorsubject – Mubramaj Oct 07 '21 at 21:45
  • I finished reading it. It still doesn't solve my doubt of why it's not being updated. I'm updating the same instance, why do I need to put the same instance to the `this.userList$`? My understanding of next() is that it's a pointer pointing to a referrence. – Chen Long Oct 07 '21 at 22:57
  • The userList is a pointer pointing to a reference. So if you look inside the value of your behaviourSubject you will see the changes even if you don't do next. However, I don't know exactly how the subscribe/next is implemented (https://github.com/ReactiveX/rxjs) but it looks like you explicitly need to push into the stream with next for a subscriber to pick up the changes. Here is a little stackBlitz that shows that inside your BehaviourSubject the changes are picked up because userList is in deed a reference https://stackblitz.com/edit/angular-playground-okkxdw?file=app/app.component.html – Mubramaj Oct 08 '21 at 10:57