159

I've read questions like Access EventEmitter Service inside of CustomHttp where the user uses EventEmitter in his service, but he was suggested in this comment not to use it and to use instead Observables directly in his services.

I also read this question where the solution suggests to pass the EventEmitter to the child and subscribe to it.

My question then is : Should I, or should I not subscribe manually to an EventEmitter? How should I use it?


  • Possible duplicate of Delegation: EventEmitter or Observable in Angular2 - Günter Zöchbauer
  • Good answer by Mark, as usual, but actually he doesn't explains why I explained. I'm not against closing it, but I want his opinion first. @MarkRajcok thoughts? - Eric Martinez
  • I would like to keep this open (and I'm sure I'll point people here -- I just edited my other answer to point here!). Your answer has a good bit of additional information. I want two question titles though... the other is "What is the proper use of an EventEmitter?" - Mark Rajcok
  • @MarkRajcok i like that title but it wouldn't fit with the current answer, so I will make sure to update it later, add examples of how to use it and how not to so it makes more sense. Thanks for your feedback :) - Eric Martinez
  • @MarkRajcok edited as suggested (y), (copy & pasted the title suggested, all credits to you). - Eric Martinez

2 답변


267

No, you should not subscribe manually to it.

EventEmitter is an angular2 abstraction and its only purpose is to emit events in components. Quoting a comment from Rob Wormald

[...] EventEmitter is really an Angular abstraction, and should be used pretty much only for emitting custom Events in components. Otherwise, just use Rx as if it was any other library.

This is stated really clear in EventEmitter's documentation.

Use by directives and components to emit custom Events.

What's wrong about using it?

Angular2 will never guarantee us that EventEmitter will continue being an Observable. So that means refactoring our code if it changes. The only API we must access is its emit() method. We should never subscribe manually to an EventEmitter.

All the stated above is more clear in this Ward Bell's comment (recommended to read the article, and the answer to that comment). Quoting for reference

Do NOT count on EventEmitter continuing to be an Observable!

Do NOT count on those Observable operators being there in the future!

These will be deprecated soon and probably removed before release.

Use EventEmitter only for event binding between a child and parent component. Do not subscribe to it. Do not call any of those methods. Only call eve.emit()

His comment is in line with Rob's comment long time ago.

So, how to use it properly?

Simply use it to emit events from your component. Take a look a the following example.

@Component({
    selector : 'child',
    template : `
        <button (click)="sendNotification()">Notify my parent!</button>
    `
})
class Child {
    @Output() notifyParent: EventEmitter<any> = new EventEmitter();
    sendNotification() {
        this.notifyParent.emit('Some value to send to the parent');
    }
}

@Component({
    selector : 'parent',
    template : `
        <child (notifyParent)="getNotification($event)"></child>
    `
})
class Parent {
    getNotification(evt) {
        // Do something with the notification (evt) sent by the child!
    }
}

How not to use it?

class MyService {
    @Output() myServiceEvent : EventEmitter<any> = new EventEmitter();
}

Stop right there... you're already wrong...

Hopefully these two simple examples will clarify EventEmitter's proper usage.

TL;DR answer :

No, don't subscribe manually to them, don't use them in services. Use them as is shown in the documentation only to emit events in components. Don't defeat angular's abstraction.


  • What do you mean by: directives : [Child] in the Component definition? This doesnt seem to compile, and I cant find it described in the Angular2 documentation. - themathmagician
  • @Eric: The how to not use it in your example is very obviously, why we need '@Output' decorator in a service? - trungk18
  • @themathmagician After a bit of research, I found here that the directives keyword has since been deprecated. Use the declarations keyword in @NgModule as directed here or here - cjsimon
  • Any comment on Toby's more recent answer? I'd guess his answer should be the accepted one nowadays. - Arjan
  • @Eric When you wrote this answer you wrote: 'These will be deprecated soon and probably removed before release', quoting Ward Bell. But this was stated 2 years ago and now we have angular6. Does this statement applies still now? I keep on seeing in the official doc that EventEmitter still has the subscribe() method, so I think that if Google wanted to stop to basing EE on Rxjs subjects they would already done it. So do you think that your original answer still fits well on the current state of Angular? - Nad G

53

Yes, go ahead and use it.

EventEmitter is a public, documented type in the final Angular Core API. Whether or not it is based on Observable is irrelevant; if its documented emit and subscribe methods suit what you need, then go ahead and use it.

As also stated in the docs:

Uses Rx.Observable but provides an adapter to make it work as specified here: https://github.com/jhusain/observable-spec

Once a reference implementation of the spec is available, switch to it.

So they wanted an Observable like object that behaved in a certain way, they implemented it, and made it public. If it were merely an internal Angular abstraction that shouldn't be used, they wouldn't have made it public.

There are plenty of times when it's useful to have an emitter which sends events of a specific type. If that's your use case, go for it. If/when a reference implementation of the spec they link to is available, it should be a drop-in replacement, just as with any other polyfill.

Just be sure that the generator you pass to the subscribe() function follows the linked spec. The returned object is guaranteed to have an unsubscribe method which should be called to free any references to the generator (this is currently an RxJs Subscription object but that is indeed an implementation detail which should not be depended on).

export class MyServiceEvent {
    message: string;
    eventId: number;
}

export class MyService {
    public onChange: EventEmitter<MyServiceEvent> = new EventEmitter<MyServiceEvent>();

    public doSomething(message: string) {
        // do something, then...
        this.onChange.emit({message: message, eventId: 42});
    }
}

export class MyConsumer {
    private _serviceSubscription;

    constructor(private service: MyService) {
        this._serviceSubscription = this.service.onChange.subscribe({
            next: (event: MyServiceEvent) => {
                console.log(`Received message #${event.eventId}: ${event.message}`);
            }
        })
    }

    public consume() {
        // do some stuff, then later...

        this.cleanup();
    }

    private cleanup() {
        this._serviceSubscription.unsubscribe();
    }
}

All of the strongly-worded doom and gloom predictions seem to stem from a single Stack Overflow comment from a single developer on a pre-release version of Angular 2.


  • This sounds reasonable- anyone else want to weigh in on this? subscribe is a public method on an event emitter after all? - Shawson
  • Ok, it's public so we are free to use it. But is there any practical reason to use EventEmitter over Observable in this example? - Botis
  • We're now on Angular v6 and EventEmmiter was not deprecated or removed so I'd say it's safe to use. However, I do see benefits to learning how to use Observables from RxJS. - David Meza

Linked


Latest