1

I am passing data between 2 independent components using shared service. When I used a subject in my shared service, I could not see the subscribed data in html of the subscribed component but could see it in the console after subscribing. Whereas if I use Behaviorsubject, it worked fine. Can anyone explain me the reason for this.

sharedservice.ts:

  //code with subject (not working)
  private msgStatistics = new Subject<any>();
      msgStatistics$ = this.msgStatistics.asObservable();
      msgStats(message) {
        this.msgStatistics.next(message)
      } 


    //code with BehaviorSubject (working)
    private msgStatistics = new BehaviorSubject<Object>(null);
      msgStatistics$ = this.msgStatistics.asObservable();
      msgStats(message) {
        this.msgStatistics.next(message)
      }

component2.ts:

this.shared_service.msgStatistics$.subscribe(res => {
        this.message = res
        console.log(this.message) 
})

the above console is printing the value of message in both the cases but it is not rendering in html for subject.

bhagya sri
  • 21
  • 1
  • 2

3 Answers3

5

The difference between Subject and BehaviorSubject is that BehaviorSubject will retain last value. Any new subscriber will receive that value.

With Subject if values emitted are received only those subscribers that are already subscribed. If a new subscriber arrives it will be late from the party and receive nothing.

You can try a simple experiment:

Create a BehaviorSubject and initialize it with some well known value. Now that values is there until next one is emitted.

Now create few subscriber to that. All of them will receive that well known value.

Do the same with Subject. You cannot initialize it so after creating it try to emit something.

Then create subscribers, nobody will receive anything.

UPDATE

I created a little demo to showcase the difference.

Once you open the Stackblitz page, you will see two columns [Subject, BehaviorSubject]

Open the console to be able to see the output. At this point no subscribers exists. You can change the value to be emitted. And then click on "Emit" Nothing will happen only a log statement that method is called.

Sample output:

onEmitSubject -> [value 4 subject]

onEmitBehaviorSubject -> [value 4 behavior subject]

Now the real test:

Create one subscriber for Subject and for BehaviorSubject.

Observe the console it should be something like this:

onCreateSubscriber4Subject

onCreateSubscriber4BehaviorSubject

BehaviorSubject Subscriber [0.03448180712702731] :: value: [value 4 behavior subject]

And here you can see the difference. Once a new subscriber arrives to BehaviorSubject it receives the last emitted value. With Subject that is not the case. Previously emitted value will not be emitted for new subscriber.

Stackblitz

robert
  • 5,742
  • 7
  • 28
  • 37
  • Yeah, I understood your point. But, I could see the console value in both the cases (in subject as well as BehaviorSubject). As per your explanation, the console should print a null value for Subject and should print a value for BehaviorSubject. – bhagya sri Aug 06 '21 at 04:34
2

Those two subjects are emitting the values before you even subscribe to it. But BehaviorSubject stores the last emitted value. So whenever something subscribe to it, it will emit the last value. That's why we create a BehaviorSubject with initial value.

In your code new BehaviorSubject(null);, you are specifying null as initial value

raju_nandu
  • 21
  • 2
1

Just to add to the answers here (Which are correct).

Subject - Does not have "memory" of what it has already emitted. Someone subscribing will only receive emits from that point on.

ReplaySubject - Has a "memory" of X amount of emits. Someone subscribing will receive X amount of emits immediately upon subscribing.

BehaviorSubject - Is essentially a ReplaySubject with a "memory" of 1, but also with a "default" value that will be emitted even if you haven't called next yet.

The reason I bring this up is because you actually are looking to use a ReplaySubject, not a BehaviorSubject. In your example you are doing the following :

private msgStatistics = new BehaviorSubject<Object>(null);

This is setting up a BehaviourSubject with a default value of null. If someone subscribes before you call next, they will actually receive a value of null. It's probably not what you want and instead you are probably looking to do :

private msgStatistics = new ReplaySubject<Object>(1);

So that it still has the memory of atleast 1 emit, but does not have a "default" value of null that you have to handle.

Some more info on the differences, including examples can be found here : https://tutorialsforangular.com/2020/12/12/subject-vs-replaysubject-vs-behaviorsubject/

MindingData
  • 11,924
  • 6
  • 49
  • 68