2

I am going through "Angular Up and Running" by Shyam Seshadri, published by O'Reilly. In the discussion on Output and the emitting of events I'm a little confused.

The EventEmitter in a component is declared, initialized and implemented as:

@Output() private toggleFavorite: EventEmitter<Stock>;

constructor() {
 this.toggleFavorite = new EventEmitter<Stock>();
}

onToggleFavorite(event) {
 console.log('We are toggling the favorite state for this stock.', event);
 this.toggleFavorite.emit(this.stock);
}

The binding in the app.component.html reads:

(toggleFavorite)="appToggleFavorite($event)"

But the method in app.component.ts is defined as:

appToggleFavorite(stock: Stock) {
 console.log('Favorite for stock ', stock, ' was triggered.');
}

If the binding is passing the $event object, and the bound method is expecting a Stock type, why does this work?

(And it does work, I've tested it.)

I am not asking what the $event object does, I already know that. Please re-read my question above carefully. I am asking: when a bound function is expecting a typed parameter, why is a binding to an EventEmitter object passing the $event object instead of an object of the expected type, and why does it seem to work (the parameter gets it's values as typed.)

  • Stock is just a types and if you will use `any` there, it will also work – Aniruddha Das Sep 17 '18 at 19:03
  • Possible duplicate of [What exactly $event object do in Angular 2?](https://stackoverflow.com/questions/37944199/what-exactly-event-object-do-in-angular-2) – Martin Adámek Sep 17 '18 at 19:06
  • No, I am not asking what the $event object does, I already know that. Please do not be off-hand, but re-read my question again carefully. Thank you. – Kevin Paul Tracy Sep 17 '18 at 19:32
  • Well, `$event` is just variable name (reserved angular keyword used to pass event payload to be precise), not a type. In your example, its type is `Stock`. Not really sure where is the question then... – Martin Adámek Sep 17 '18 at 19:38
  • Why, then, isn't the stock parameter, regardless of type, being replaced with the $event object and all of it's parts? Instead, it is being populated with the correct data for the Stock in question. But how? – Kevin Paul Tracy Sep 17 '18 at 19:54
  • I think some crossover is happening involving the this.toggleFavorite.emit(this.stock); line in the declaring/implementing component (above.) – Kevin Paul Tracy Sep 17 '18 at 20:01

3 Answers3

2

Technically, the $event is unecessary and create confusion.

(toggleFavorite)="appToggleFavorite()"

will work as well, since you're implying that when you call .emit, you will call appToggleFavorite with any value type given to .emit. And Javascript is an untyped language, so it will work at run time.

JFPicard
  • 5,029
  • 3
  • 19
  • 43
0

My best guess would be, carefully have a look at the appToggleFavorite function below.

appToggleFavorite(stock: Stock) {
 console.log('Favorite for stock ', stock, ' was triggered.');
}

If it were to be called at Compile time, it would have thrown an error saying that appToggleFavorite is expecting an arg of type Stock but isn't given one.

But appToggleFavorite is getting called at runtime, and at runtime, its just HTML and JavaScript. It doesn't care what is received as an arg to appToggleFavorite. And thus it works.

Just to give you a brief, the Child Component can let the Parent Component know about something via an Output property on it. This Output property will then be used by the Parent Component's Template as an event. So to listen for the Output property, an Event Binding would be required. The Handler Function that is assigned to this Event Binding will be called as soon as the emit method is called on the EventEmitter that was exposed as an Output property. The Handler function will only be able to get a hold of the data that was passed to the emit function only if the reserved keyword $event is used.

SiddAjmera
  • 38,129
  • 5
  • 72
  • 110
  • Yes, I'd like to see the two compile stages as this code is broken down into Javascript, I think I might better understand what's going on "behind the curtain" here, so to speak. Somehow the stock parameter is getting populated with correct data, even though the binding is passing the $event object instead. Why? – Kevin Paul Tracy Sep 17 '18 at 19:50
  • Like I said, it's being called at runtime. It's basically a handler to an event which like any DOM Event would be called at runtime, in the future, after the App has compiled. – SiddAjmera Sep 17 '18 at 19:51
  • Okay, maybe I'm being slow here, but wouldn't the parameter then hold the data for $event and all if it's parts? It isn't, it's getting the stock data it needs. Where is it getting it, if $event is being passed instead? – Kevin Paul Tracy Sep 17 '18 at 19:57
  • No. It would hold only the data that was emitted here: `this.toggleFavorite.emit(this.stock);` – SiddAjmera Sep 17 '18 at 19:58
  • Thank you, that's the answer I was locking for. – Kevin Paul Tracy Sep 17 '18 at 20:39
0

It's a Advanced Type of TypeScript, not from Angular. When you declare:

@Output() private toggleFavorite: EventEmitter<Stock>;

The type of toggleFavorite is <Stock> and the compiler is "waiting" this type in return of value.
The doc of this is right here.

Gaspar
  • 1,515
  • 13
  • 20
  • I don't think it's because of Generics. `@Output() private toggleFavorite: EventEmitter;` would work as well. – SiddAjmera Sep 17 '18 at 20:11
  • THANK YOU! This answer and the prior one clarified what I thought might be happening but was having trouble articulating! – Kevin Paul Tracy Sep 17 '18 at 20:12
  • Yes, because `` accept anything. If you put `` will accept ``? – Gaspar Sep 17 '18 at 20:12
  • Yeah, but according to your point, it should work in case of the `appToggleFavorite(stock: Stock)` as it's only accepting `Stock` but is given any. But it would work. – SiddAjmera Sep 17 '18 at 20:14
  • It's just for _protect/clarify_ your code, if you want to be free, put `any` and like @SiddAjmera said will accept anything – Gaspar Sep 17 '18 at 20:14
  • Yes, the `onToggleFavorite` return type is `any`, if he puts `onToggleFavorite(event: foo)` may cause error – Gaspar Sep 17 '18 at 20:17
  • Sorry, i know what's wrong now, I will edit my answer – Gaspar Sep 17 '18 at 20:20