DEV Community

Cover image for Why EventEmitters instead of Subjects in Angular
Massimo Artizzu
Massimo Artizzu

Posted on

Why EventEmitters instead of Subjects in Angular

Recently I was thinking about how Angular uses the awesome library RxJS, and specifically when observable objects are created and expected.

One of them is the EventEmitter class that's used solely for emitting custom events in @Output-decorated properties, like this:

@Component({ ... })
class MyTab {
  @Output() selected = new EventEmitter<void>();
Enter fullscreen mode Exit fullscreen mode

But what are EventEmitters? Why are they used for @Output properties only? What do they add to the mix?

It turns out that the class EventEmitter, as of Angular 11.2.3, extends RxJS' Subject, adding just two things to the mix:

  • an emit method that internally just calls;
  • an optional, less-known constructor argument isAsync (defaulting to false), that schedules the event emission on a subsequent task upon subscription (using the plain old setTimeout).

That's it. EventEmitters don't automatically complete when the view is destroyed (that would be great, IMO). They don't do anything special, but the async option could be useful somewhere else, right?

But digging a little deeper, it looks like the Angular team initially designed EventEmitter to be an extension of Subject out of... convenience? And had something else in mind that could probably not involve observables at all. That's why Ward Bell stated you shouldn't use EventEmitters for anything else than @Output properties, and none should pipe them or subscribe to them.

But... that comment is five years old. And nothing has changed since then. EventEmitter still extends Subject, and I know for a fact that there's code in production that explicitly subscribes to EventEmitters, or that uses simpler observables for @Output properties. And now the fact that EventEmitter extends Subject is also explictly mentioned in the official documentation.

I think the Angular team should set this in stone and call it a day. I see no reason to change the observable nature of Angular's custom events.

Maybe I'm missing something here, and anything can change in the future. For the time being, I'll still refrain from using EventEmitters for anything that they're not supposed to be used for, just in case. (Also because they don't actually add much. And the class name is pretty specific, and misleading if not used for... emitting events, duh.)

But coding @Output properties that are not EventEmitters... eh, that could actually be useful and simplify some code. With caveats.

Top comments (0)