4

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();
    }
}

2 Answers 2

11

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

Sign up to request clarification or add additional context in comments.

11 Comments

Thnx Dennis. Im still curious about some related / lingering functionality. What is the correct EventEmitter syntax to used to subscribe to a particular "channel" as we did in angular 1 $Broadcast and $on? In order to achieve a "channel", I just create a second new EventEmitter variable or just a new/2nd closure variable bound to the existing _emitter variable? ... = this._emitter.toRx(); $scope.$broadcast('myCustomEvent', { someProp: 'Sending you an Object!' // send whatever you want }); $scope.$on('myCustomEvent', function (event, data) { console.log(data); // 'Data to send' });
To be honest, in my uses I jump the EventEmitter and go straight to creating a new observable(the whole .toRx() thing at the moment is a pain) then put it in a holding object. I feel like the EventEmitter is more suited to communication in components Vs a service.(IMO) You would want to create a new one per "channel" otherwise you'd need filtering logic every time the stream updated. Then I just call: myObserverService.observers.myCustomEvent.subscribe(...) OR you could make a helper in your service and have something like: myObserverService.listen('myCustomEvent',(data)=>{},(error)=>{})
I was thinking about this over the weekend and I missed a big point of what you wanted. You should for sure use the EventEmitter for the pub/sub nature of your plan. That way you can easily do .next() from other functions.
This is a good solution, but you forget to unsubscribe the event handlers. If you don't unsubscribe it, the handler will be called multiple time if you have multiple instances of that component. I find an 'unsubscribe' method but it doesn't work as expected
Thats only if you want a single response, if thats the case you can call complete() inside the caller. Externally it looks like you can use dispose() (RxJS subject) but I've never tested that...
|
5

In Beta version you no longer need to convert it to RxJs object by toRx().

var evtEmitter = new EventEmitter();

evtEmitter.emit(args);
evtEmitter.subscribe((args)=>{console.log('new event')});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.