7

I'm using a shareDataService using BehaviorSubject like below. My problem is that every time I call the service's next() method the listener subscription in any other component is called several times, looks like it received the same message several times. Is this expected behavior? How to prevent it?

The service is a singleton. I do not call changeMessage multiple times

@Injectable()
export class ShareDataService {

    messageSource = new BehaviorSubject(someData);
    currentMessage: Observable = this.messageSource.asObservable();
    changeMessage(message) {
        this.messageSource.next(message);
    }

}

Subscription in component

ngDoCheck() {
    this.shareDataService.currentMessage
        .pipe(takeUntil(this.ngUnsubscribe))
        .subscribe((message) => {
            //Do stuff
        }
    });
}
Mac_W
  • 2,927
  • 6
  • 17
  • 30
  • Can you log the order of the success callbacks from all subscriptions and show us? BehaviorSubject is supposed to emit the last (Previously emitted data and the current emitted data as well) But Just to make sure please show the logs which will contain all occurences of success callbacks – Vinod Bhavnani Jul 23 '18 at 11:57
  • 1
    `next(...)` sends the value to all observers (subscribers). You might be creating multiple subscriptions in the same component. – martin Jul 23 '18 at 11:58
  • Can you post the code where you actually subscribe? – David R Jul 23 '18 at 11:58
  • @DavidR - just added – Mac_W Jul 23 '18 at 12:18
  • @martin - what do you mean? I only subscribe once in multiple components – Mac_W Jul 23 '18 at 12:18

3 Answers3

13

A new subscription is added every time ngDoCheck() is called. Try using first() to only get the value once and then automatically unsubscribe.

ngDoCheck() {
    this.shareDataService.currentMessage
        .pipe(first())
        .subscribe((message) => {
            // Do stuff
        }
    });
}

The next time ngDoCheck is triggered, it adds another one-time subscription.


If your only intention of the subscription is to get the current value on change detection, you can also add a simple get() function to your ShareDataService to just return its current value.

get() {
    return this.messageSource.getValue();
}
Jeffrey Roosendaal
  • 6,872
  • 8
  • 37
  • 55
  • 1
    I now what the issues is now! It is now sending multiple messages, it just gets triggered on change detection! – Mac_W Jul 23 '18 at 15:06
  • @Willys I think,, because both have an active subscription, so when one of them triggers next(). both the subscriptions fire, and causing both reloads() to fire (again). – Jeffrey Roosendaal May 21 '19 at 15:15
  • @JeffreyRoosendaal Thanks for reply. What about the solution regarding to that issue? I created subject and get event for each method but I am not sure if it is a good idea? Could you pls post your suggestion to that question? – Jack May 21 '19 at 19:40
3

Can you please try calling the unsubscribe in your ngOnDestroy() lifecycle hook

ngOnDestroy() {
    this.shareDataService.currentMessage.unsubscribe();
}

Hope this helps!

David R
  • 14,711
  • 7
  • 54
  • 72
-1

I also faced similar issue and i find I did not destroyed my next().

Please check below code and add it in your onDestroy. I hope it may help you!

ngOnDestroy() { this.messageSource.next(); }

All The Best!!!

Ambuj Khanna
  • 1,131
  • 3
  • 12
  • 32