0

On an Angular 10 application I need to send a message between components so I created the service:

export class MemoService {

  private subject = new Subject<Memo>();

  send(code: MemoCode, data?: any) {
    this.subject.next(new Memo(code, data));
  }

  clear() {
    this.subject.next();
  }

  get(): Observable<Memo> {
    return this.subject.asObservable();
  }

}

On a component consuming this service I have:

  private memo: Subscription;

  private user: BehaviorSubject<User> = new BehaviorSubject<User>(null);


  constructor(private memoService: MemoService) { 

    this.getUser().subscribe((result: GetUserResponse) => this.user.next(result));

    this.memo = this.memoService.get().subscribe((memo: Memo) => { 

      if (memo.code == MemoCode.AuthenticatedUserModified) 
        this.getUser().subscribe((result: GetUserResponse) => this.user.next(result));

    });

  }

The idea is when a specific User is updated I send a Memo to other components using the MemoService.

Question

Should I use Subject or BehaviorSubject in both Component and Service?

Miguel Moura
  • 36,732
  • 85
  • 259
  • 481
  • https://stackoverflow.com/questions/43348463/what-is-the-difference-between-subject-and-behaviorsubject – Phix Sep 15 '20 at 18:19
  • what is the purpose of using subject in the component? – Rafi Henig Sep 15 '20 at 18:21
  • @RafiHenig Any moment ComponentA sends a new Memo ComponentB needs to know about it and act accordantly the MemoCode. You're saying that MemoService's subject should be only an Observable? – Miguel Moura Sep 15 '20 at 18:30
  • 2
    I would suggest of using a single BehaviorSubject/ReplaySubject in the service – Rafi Henig Sep 15 '20 at 18:39
  • I think I will ReplaySubject as it seems similar to BehaviorSubject but without an initial value which I don't have. – Miguel Moura Sep 15 '20 at 18:53
  • I would rather recommend using simple setter and getter to achieve this, check this out https://stackoverflow.com/questions/63896191/how-to-access-variable-of-subscribe-block-of-behaviour-subject-outside-the-block/63897453#63897453 – Kamran Khatti Sep 15 '20 at 19:15
  • @KamranKhatti What if a new value is sent? – Miguel Moura Sep 15 '20 at 19:42
  • 1
    @MiguelMoura you can set new value from any component using that service set method, same as you set value in subject. – Kamran Khatti Sep 15 '20 at 19:45
  • @MiguelMoura What is the use of `user: BehaviorSubject` in the component? I mean what is the role it is playing to notify other components? – user2216584 Sep 15 '20 at 22:42
  • @user2216584 It is used to display the user.name in a menu, to check if the user has a Role and can view or not part of the UI, ... – Miguel Moura Sep 16 '20 at 17:50

2 Answers2

1

The idea is when a specific User is updated I send a Memo

I think you might be making it harder than necessary. You may not need the "MemoService" at all!

The idea with observables is that you can subscribe and always have the latest value automatically. Your subscription to getUser() should already produce the updated value when changes occur. There should be no need for consuming components to re-emit values.

In this case, the only place a Subject would be needed, is in your UserService.

export class UserService{

  private user = new BehaviorSubject<User>(undefined);
  public user$ = this.user.asObservable();

  setUser(user: User) {
    this.user.next(user);
  }

  updateUser(changes: Partial<User>) {
    const updatedUser = { ...this.user.value, ...changes };
    this.user.next(updatedUser);
  }
}

Then, your component code is super simple:

class SomeComponent {
  constructor(private userService: UserService) { }

  public user$ = this.userService.user$;
}

Any component can call userService.setUser() and all interested components will automatically receive the updated value.

Notice you don't even need to subscribe in the controller and can simply use the async pipe in your template:

<div *ngIf="user$ | async as user">
  <h1>Hello {{ user.name }}!</h1>
</div>
BizzyBob
  • 12,309
  • 4
  • 27
  • 51
-1

What you're trying to do seems to be state management, i.e. managing shared state between components. If that's the case, I would strongly advise against using manual solutions like services and subjects, but rather use some battle-tested state management library. Some good ones are:

https://datorama.github.io/akita/

https://ngrx.io/

https://www.ngxs.io/

afrish
  • 3,167
  • 4
  • 30
  • 38
  • Yes, I am kind of doing that but only in a simple case ... Using one of those, at least for now, would be to much in this specific case. That is why I created this simple service. – Miguel Moura Sep 15 '20 at 19:43