What is the proper use of an EventEmitter?
Asked Answered
D

5

313

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?

Duckpin answered 18/3, 2016 at 5:20 Comment(6)
Possible duplicate of Delegation: EventEmitter or Observable in Angular2Mosier
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?Duckpin
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?"Quag
@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 :)Duckpin
@MarkRajcok edited as suggested (y), (copy & pasted the title suggested, all credits to you).Duckpin
I am taking note of the comments and the answer, should I be concerned if any 3rd party libs are using EventEmitters from Services?Cris
D
436

TL;DR:

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.

Answer:

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.

Duckpin answered 18/3, 2016 at 5:20 Comment(21)
Does / will EventEmitter at least implement the RxJS 5 Observer interface? It would be useful to do something like myObservable.subscribe(myEventEmitter).Virility
Does this answer change if I am using an injectable service that contains an event emitter? (rc5)Toffey
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.Blab
I have a service which is used as a provider in a component. I make a data call in the service. I thought we could create a emitter in the service and emit an event and subscribe for that event in the component once we receive the data. But you are saying we shouldn't subscribe. What would be the best way to emit event from service to the component?Cautery
@Eric: The how to not use it in your example is very obviously, why we need '@Output' decorator in a service?Coiffeur
Is it ok to listen to / handle events emitted this way in services?Bobette
@Eric: Can you share your knowledge on communicating between sibling components A and B, where A is directly loaded while B comes within a sibling <router-outlet>? From my understanding, we will have to subscribe() the emit(), in this case right.Silverside
Thanks for the info Eric. Can I use the event to notify from child to parent? or is this just supose to be a parent to child thing?Westward
@Blab 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 hereLemaster
I have a question, should we manually complete them. I've seem complete code in angular/material2Insuppressible
And how to emit events to a sibling component? (the case when there's no parent child but sibling components).Almagest
How to achieve the same vice-versa? i.e., from Parent Component to child component.Faeroese
After a year (plus months) of the answer posting, is there any use case for injectable service implementation of EE?Bouffant
Any comment on Toby's more recent answer? I'd guess his answer should be the accepted one nowadays.Recitative
@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?Circumvallate
Angular's EventEmitter docs give the example "@Output() open: EventEmitter<any> = new EventEmitter();" so by now, I think we're good with Tobias' answer.Eonism
Subscribe is now a documented public API and may be used. The underlying implementation is irrelevant.Wincer
plus one for the really large font for the answer in the beginningWynd
@AndrewKoper I'd argue that the need for a large font, or overtures of emotion are not needed, if the answer is truly correct.Whisenant
@NadG I've learned a long time ago not to base my code on someone else's agenda - even Google's.Whisenant
Never use your opinion and say it must 100%. You can utilize it for decouple code relationship (e.g between some method use socket...). Of cause use can have many way to solve this but EventEmit still a good option to considerCaughey
C
142

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.

Cestode answered 7/11, 2017 at 20:46 Comment(7)
This sounds reasonable- anyone else want to weigh in on this? subscribe is a public method on an event emitter after all?Brosine
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?Circumference
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.Orton
I see it as "if you're using EventEmitter outside of @Output, no need to rush changing it to something else as the api is stable ATM"; if you have time or the api breaks you'll have to change it (but keep in mind that for angular to change a public stable api (emit and subscribe) is not common). Also stick to the public api, don't access methods of Subject or Observable that are not defined in EventEmitter to stay on the safer sideTeratogenic
The assumption that something is safe to use because of "not been removed from Angular" or "well documented" is wrong as well as The nono policy proposed above. You create a project not for the reason of future versions of angular. There are plenty of not mantained platforms outside there still working on the web. The version of the framework doesn't make developers who were working on those platforms less developers or developers of B category.Pattipattie
What about the angular upgrade tool? If they change the specification of eventemitter, would the upgrade tool update the syntax to match any future patterns? As long as there is a tool that will prevent most manual changes, per lean / six-sigma, seems like it is valid to use eventemitter like a observable (including unsubscribe ngOnDestroy or other method).Walworth
This is the latest official answer on this topic, and it basically says: they will not officially give any guarantees, so while it's unlikely to change, you are in your own with it.Psychodynamics
B
8

When you want to have cross component interaction, then you need to know what are @Input , @Output , EventEmitter and Subjects.

If the relation between components is parent- child or vice versa we use @input & @output with event emitter..

@output emits an event and you need to emit using event emitter.

If it's not parent child relationship.. then you have to use subjects or through a common service.

Beaulieu answered 27/4, 2019 at 10:9 Comment(0)
P
1

There is no: nono and no: yesyes. The truth is in the middle And no reasons to be scared because of the next version of Angular.

From a logical point of view, if You have a Component and You want to inform other components that something happens, an event should be fired and this can be done in whatever way You (developer) think it should be done. I don't see the reason why to not use it and i don't see the reason why to use it at all costs. Also the EventEmitter name suggests to me an event happening. I usually use it for important events happening in the Component. I create the Service but create the Service file inside the Component Folder. So my Service file becomes a sort of Event Manager or an Event Interface, so I can figure out at glance to which event I can subscribe on the current component.

I know..Maybe I'm a bit an old fashioned developer. But this is not a part of Event Driven development pattern, this is part of the software architecture decisions of Your particular project.

Some other guys may think that use Observables directly is cool. In that case go ahead with Observables directly. You're not a serial killer doing this. Unless you're a psychopath developer, So far the Program works, do it.

Pattipattie answered 6/6, 2019 at 11:44 Comment(0)
G
0

From a pure implementation perspective, since emit and subscribe are part of the public interface of EventEmitter, they can be used for implementation.

For angular there was no compulsion to inherit from behaviour if it didn't want it to, Behaviour could have been a private member in EventEmitter class, something like,

public class EventEmitter{
  private _behaviour=new Subject<void>();
  private _behaviour$=this._behaviour.asObservable();
  ......
  public emit(){
    _behaviour.emit();
  }
  ....
}

If it inherits from Behvaiour but doesn't behave like one, then it is violation of liskov's susbstitution principle.

Garnes answered 21/10, 2021 at 7:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.