Benjamin McFerren Benjamin McFerren - 2 months ago 37
AngularJS Question

Angular 2 EventEmitter - Broadcasting next( ... ) from a Service function

To my understanding, the .toRx().subscribe( ... ) function is meant to RECEIVE messages and the .next() function is meant to BROADCAST messages

In this plnkr ( http://plnkr.co/edit/MT3xOB?p=info ) , you invoke the .toRx().subscribe( ... ) function from a data object that seems to be defined/derived originally from the template:

@Component({
selector : 'child-cmp',
template : '',
inputs : ['data']
})
class ChildCmp {
afterViewInit() {
this.data.toRx().subscribe((data) => {
console.log('New data has arrived!', data);
});
}
}


In this plnkr ( http://plnkr.co/edit/rNdInA?p=preview ) , you invoke the .toRx().subscribe( ... ) function from an evt object and its emitter function (originating from Service injected into the component's constructor)

@Component({
selector : 'parent-cmp',
template : ''
})
class ParentCmp {
constructor(evt: EventService) {
evt.emitter.subscribe((data) =>
console.log("I'm the parent cmp and I got this data", data));
}
}


Is is possible for the BROADCAST to take place in a function of the Service itself while at the same time, is it possible for the Component to RECEIVE the message without relying upon a returned Service object or Template data object to chain its .toRX().subscribe( ... ) function invokation?

import {Injectable, EventEmitter} from 'angular2/angular2';
@Injectable()
export class DataService {
items:Array<any>;
dispatcher: EventEmitter = new EventEmitter();
constructor() {
this.items = [
{ name: 'AAAA' },
{ name: 'BBBB' },
{ name: 'CCCC' }
];
}
getItems() {
return this.items;
}
sendItems() {
this.dispatcher.next( this.items );
}
}
export var DATA_BINDINGS: Array<any> = [
DataService
];


@Component({
selector: 'rabble'
})
@View({
...
})
export class Rabble {

items : Array<any>;

constructor( public dataService : DataService) {

console.log('this.routeParam', this.dataService.getItems());
}

afterViewInit() {
this.???.toRx().subscribe((data) => {
console.log('New item data has arrived!', data);
});
}

handleClick() {
this.dataService.sendItems();
}
}

Answer

UPDATED TO 2.0 Stable: EventEmitter is now solely for component communication. This is a better use for Subjects and ReplaySubjects. I've updated the examples to 2.0 code.

UPDATED TO BETA 1: You no longer need to call .toRx() on the emitter so I'm updating the code to match and added an example to unSubscribe.

So right now (Alpha 45) The eventEmitter has that toRx() method which returns a RxJS SUBJECT

You can google a bit what that is and what you can do with it but it's what you are actually messing with. When you call toRx() it just returns the internal subject from the eventEmitter so you can do that in your service constructor.

Then I added the function you wanted to do the broadcast to the event service

class EventService {
  //could be regular Subject but I like how ReplaySubject will send the last item when a new subscriber joins
  emitter: ReplaySubject<any> = new ReplaySubject(1);
  constructor() {

  }
  doSomething(data){
    this.emitter.next(data);
  }
}

Then in your component you subscribe to the emitter

class ParentCmp {
  myData: any;
  constructor(private evt: EventService) {
    //rx emitter
    this.evt.emitter.subscribe((data) => {
      this.myData = data;
      console.log("I'm the parent cmp and I got this data", data));
    }
  }
}

And here is a expanded class with a built in unsubscribe(dispose)

export class ParentCmp implements OnDestroy {
  myData: any;
  subscription: any;
  constructor(evt: EventService) {
    //rx emitter
    this.subscription = evt.emitter.subscribe((data) => {
      this.myData = data;
      console.log("I'm the parent cmp and I got this data", data));
    }
  }
  ngOnDestroy() {
    this.subscription.dispose();
  }
}

I'm a little confused about your last question but think of the term "receive a message." You have to be listening to something so thats what the subscribe method does and is required.

Cool thing is now you can call that observable all over the place (even in other services) and IMO is the best way to communicate between components. They don't need to know their position in the tree or care if the other components exist or are listening.

I Forked your Plunker with my way working HERE (still on Alpha45)

RxJs source and info on subject

Angular2 source and info on the subject inside the eventEmitter

Comments