39

I am building a service which exposes an Observable. In this service I receive external function calls which should trigger a next call on the Observable so that various consumers get the subscribe event. During Observer constructor I can call next and everything works great, but how can I access this outside of the constructor so that external triggers can fire next calls?

private myObservable$: Observable<any>; 

During service init I do

this.myObservable$ = new Observable(observer => { observer.next("initial message"); } 

Then in other methods of the same service I want to be able to execute something like

this.myObservable$.observer.next("next message"); 

The above obviously doesn't work, but how can I accomplish this goal?

I'm assuming I'm missing something basic since there must be a way to emit further messages outside of the Observable's initial constructor

5 Answers 5

53

You should create a Subject for that

this.myObservable$ = new Subject(); 

And then you can call at any point:

this.myObservable$.next(...); 

Or use subscribe:

this.myObservable$.subscribe(...) 
Sign up to request clarification or add additional context in comments.

4 Comments

This is pure rxjs - it has nothing to do with angular.
Note: Only subscriptions setup before calling next will receive new values. If you want to allow subscriptions created afterwards use BehaviorSubject or ReplaySubject.
that is the best way to trigger anything from any point through service in angular.
Relevant because what @olsn said imgflip.com/i/6i16c0
14

Actually Subject is used for both publisher and subscriber, and here I think you need only to publish your value, so simply use Observable.

By using observable, assign Subscriber to class level variable and then use it, like below code

subscriber: Subscriber<boolean>; public observe(): Observable<boolean> { return new Observable<boolean>(subs => { this.subscriber = subs; }); } public callNext() { if (this.subscriber) { this.subscriber.next(); this.subscriber.complete(); } } 

1 Comment

Duh. I was trying to go the other way by passing the Subscriber into the constructor. This should be the accepted answer.
6

Two ways:

  1. Make myObservable$ public:

    public myObservable$: Observable; 
  2. Encapsulate the observable in a subject stream, and provide a helper to call next:

    export class TestService { public myObservable$: Observable; private _myObservableSubject: Subject; constructor() { this._myObservableSubject = new Subject(); this.myObservable$ = this._myObservableSubject.asObservable(); } public NextMessage(message?: string): void { this._myObservableSubject.next(message); } } 

4 Comments

Thanks Boyan, the second looks like it'd work but I'm going with olsn's answer above, seems much more concise.
Sure, we are talking about the same thing. I got my answer from reading the Angular 2 docs. Specifically this section, angular.io/docs/ts/latest/cookbook/…
Subject extends Observable, so you don't need this wrapper. Just use Subject.
Unfortunately, the subject can only have one subscriber if i'm not wrong, not the same behaviour
3

Observable: You have to call the next() function from inside the constructor and only one time you can subscribe

message = new Observable((observer)=>{ observer.next(9); }) this.messsage.subscribe((res)=>{ console.log(res) }) output: 9 

Subject: You have to call next() function from outside the constructor and multiple times you can subscribe. The subject does not store any initial value before subscribe.

messsage = new Subject() this.messsage.next(3) this.messsage.subscribe((res)=>{ console.log(' A '+res) }) this.messsage.next(4) this.messsage.next(5) this.messsage.subscribe((res)=>{ console.log(' B '+res) }) this.messsage.next(6) output: A 4 A 5 A 6 B 6 

BehaviorSubject: You have to call next() function from outside the constructor and multiple times you can subscribe. The BehaviorSubject does store only one initial value before subscribe.

messsage = new BehaviorSubject () this.messsage.next(3) this.messsage.subscribe((res)=>{ console.log(' A '+res) }) this.messsage.next(4) this.messsage.next(5) this.messsage.subscribe((res)=>{ console.log(' B '+res) }) this.messsage.next(6) output: A 3 A 4 A 5 B 5 A 6 B 6 

1 Comment

I liked it.. so subject advanced version of observable?
2

I ended up combining a couple of things:

  • olsn's answer, which nicely demonstrates Subject's ease of use
  • Ravi's answer, which correctly points out that we only want an Observable exposed
  • a more functional approach, because this and Class give me the shivers
  • TypeScript typings for generic use
const createObservableWithNext = <T>(): { observable: Observable<T>; next: (value: T) => void; } => { const subject = new Subject<T>(); const observable = subject.asObservable(); const next = (value: T) => subject.next(value); return { observable, next, }; }; 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.