4

I am trying to create event broadcast service.

Here is basic concept what I would like to achieve:

export enum Event {
   EVENT_A,
   EVENT_B, ...
}


@Injectable()
export class BroadcastService {

     private broadcastSubject: Subject<Event> = new Subject<Event>();

     public next(event: Event): void {
         return this.broadcastSubject.next(event);
     }

     public subscribe(event: Event, componentCall: Function): void {
         this.broadcastSubject.subscribe(
             eventValue => {
                if(event === eventValue) {
                  componentCall(); // not possible to call component's method like this
                } 
             }
        );
   }
}

I know I can't call component's method from service like this. I have to return observable somehow and call it from component. I am not sure how to achieve this.

Thanks for any advice.


SOLUTION

Thanks to AngularFrance, here is solution for the BroadcastService:

@Injectable()
export class BroadcastService {

  private broadcastSubject: BehaviorSubject<Event> = new BehaviorSubject<Event>(0);

  public next(event: Event): void {
     return this.broadcastSubject.next(event);
  }

  public subject(event: Event): Observable<Event> {
     return this.broadcastSubject.asObservable().filter(e => e === event);
  }

}
Community
  • 1
  • 1
Tomas Marik
  • 4,053
  • 3
  • 31
  • 62

2 Answers2

5

You should return the observable from BroadcastService (NB. A Subject is an Observable):

@Injectable()
export class BroadcastService {

     private event: Subject<Event> = new Subject<Event>();

     public next(event: Event): void {
       return this.event.next(event);
     }

     public getEvents(event: Event): Observable<Event> {
       // DO NOT SUBSCRIBE HERE. Return the observable.
       return this.event.asObservable()
         // Only keep events matching the given `event` param
         .filter(e => e == event);
     }
}

Then subscribe to the returned observable from a component:

export class MyComponent {

  constructor(bcservice: BroadcastService) {
    // Subscribe here.
    bcservice.getEvents(event).subscribe(eventValue => {
      this.someMethod();
    });
  }

  someMethod() { }

}

NOTE: If you only ever want a specific type of events in the stream, it might be more optimal to filter out unwanted events before adding them to the stream (in the next() method) as opposed to when returning the stream.

AngularChef
  • 13,797
  • 8
  • 53
  • 69
  • Thanks, for the answer. But what I would like to achieve is that the /* test eventValue */ will be in BroadcastService, otherwise there is no point of wrapping Subject into BroadcastService. – Tomas Marik Feb 16 '17 at 11:32
  • You're saying you only want to call your method for certain events? – AngularChef Feb 16 '17 at 11:34
  • Yes, I would like to subscribe just for one event: subscribe(event: Event, ...). – Tomas Marik Feb 16 '17 at 11:35
  • Then I suggest you pass a param to `getEvents()` (like you did in your original code) and use that param to filter the observable with the `.filter()` operator. See my updated answer. – AngularChef Feb 16 '17 at 11:39
  • Well this is exactly what I was looking for. Thanks! – Tomas Marik Feb 16 '17 at 11:50
0

Why you are not using events form Angular 2: https://angular.io/docs/ts/latest/api/core/index/EventEmitter-class.html

Or even better Rx: https://medium.com/google-developer-experts/angular-introduction-to-reactive-extensions-rxjs-a86a7430a61f#.dsaecx6sc

Here you also have a sample: https://github.com/ng-book/angular2-rxjs-chat

patrick
  • 826
  • 1
  • 9
  • 28
  • 1
    Well it doesn't seem like good idea: http://stackoverflow.com/questions/36076700/what-is-the-proper-use-of-an-eventemitter – Tomas Marik Feb 16 '17 at 11:20