Search code examples
javascriptangulartypescriptoutputeventemitter

TypeScript | JavaScript | Angular 2 | @Output vs @Input


Whyyyyyyyyyyyyyyy?

Dear Reader,

I've searched high and low, but nobody can explain this without a huge leap of faith to just say, "Here are the effects!", or "This is how you do that! Don't ask why!"

The issue

class ChildComponent {
    @Output selected: EventEmitter<T>() = EventEmitter<T>();
    @Input item;
    handleClick(e, t) {
        ...
        this.selected.emit(t);
    }
}

class ParentComponent {
    items = [];
    handleSelection(type) {
        ...
    }
}

Parent Template

<child-component [item]="item" (selected)="handleSelection(item)" *ngFor="let item of items">
    {{item.name}}
</child-component>

For whatever reason, nobody can explain this syntax in anything remotely abstract. Every answer is so unbearably concrete that any meaning is lost outside of the specificity of defining events at the component level, where only the direct parent has access -- and, there's virtually no reason whatsoever to use @Output/EventEmitter instead of @Input/callback.

Question

@Output isThisAUselessVariable; Given that this "output" is undefined -- moreover, has nothing to do with EventEmitter -- what in Poseidon's sake would I do with this? At this point, what can I even use it for? Is it utterly useless now? What if it has a value, but the value is an Array or an Object? What about a String? How may I use @Output without using EventEmitter?

That seems like odd questioning here, but I want to avoid answers of "Because you can use it for events. If you want an event, use this! This is how you do events! Why??? I don't know! Just remember the magic event syntax!"

Further Questions & Curiosities

A)

Why the nomenclature "@Output"? What makes it an "output"?


B)

Aside from potential benefits of Message Coupling, why not use @Input with callbacks?


C)

Is messaging the only reason why I'd use @Output? What else is/can it be used for? [ SEE 'A' ]


D)

Who can listen for this event? Can a great-grandparent listen without having to pass in a handler directly to the child/great-grandchild and manually bubble it? [ SEE 'B' ]


E)

I'm used to messaging being global or bubbling, and well-designed Event-Driven Architectures to define Event-Types at the Application-Scale -- not the Component-Scale. This allows for different types of "Message Filtering" (SEE Wikipedia), and allows us to use an Application Mediator.

Why would I want to use this at the component scale? How can I define events on a higher scale and use them on a lower scale?


F)

How can I mediate these events? [ SEE 'E' ]


Tons of Appreciation,

Cody


Solution

  • If you annotate a variable with @Output it has to be of the type EventEmitter. The name of the variable becomes the name of the custom event. Messaging is the only reason for using @Output. You're sending an event without caring who's interested in getting it. Angular doesn't support event bubbling, but you can implement it with native DOM events.

    IMO, using events offers a more loosely coupled architecture in inter-component communication than passing callbacks. In this blog I showed how to use callbacks with @Input params: https://yakovfain.com/2016/10/31/angular-2-component-communication-with-events-vs-callbacks/

    In this video I showed one of the ways of mediating using @Input, @Output, and the parent component as a mediator: https://www.youtube.com/watch?v=tSXx4NoKEYY Using an injectable service as a mediator offers more flexibility though.