I'm looking for an argument on why using @Output
for events is better than passing an @Input
function in Angular 2+.
Using @Input
:
Parent Template:
<my-component [customEventFunction]=myFunction></my-component>
Inside parent-component.ts:
myFunction = () => {
console.log("Hello world")
}
Inside my-component.ts
@Input() customEventFunction: Function;
someFunctionThatTriggersTheEvent() {
this.customEventFunction();
}
Using @Output
:
Parent Template:
<my-component (onCustomEvent)=myFunction()></my-component>
Inside parent-component.ts:
myFunction() {
console.log("Hello world")
}
Inside my-component.ts
@Output() onCustomEvent: EventEmitter<any> = new EventEmitter<any>();
someFunctionThatTriggersTheEvent() {
this.onCustomEvent.emit();
}
Both achieve the same goal, but I think that the @Output
method is more typical from what I've seen in other Angular packages. One could argue that with an Input, you can check to see if the function exists if the event should only be triggered conditionally.
Thoughts?
The advantages of @Output event binding:
onmousemove="doSomething()"
while the @Output event binding is more like calling btn.addEventListener("mousemove", ...)
.@Sajeetharan's answer actually isn't quite correct: there is a significant functional difference: the execution context. Consider this scenario:
@Component({
selector: 'app-example',
template: `<button (click)="runFn()">Click Me</button>`,
})
export class ExampleComponent {
@Input() public fn: any;
public runFn(): void {
this.fn();
}
}
@Component({
selector: 'app',
template: `<app-example [fn]="myFn"></app-example>`,
})
export class AppComponent {
public state = 42;
// Using arrow syntax actually *will* alert "42" because
// arrow functions do not have their own "this" context.
//
// public myFn = () => window.alert(this.state);
public myFn(): void {
// Oops, this will alert "undefined" because this function
// is actually executed in the scope of the child component!
window.alert(this.state);
}
}
This actually makes it pretty awkward to use @Input()
properties to pass functions. At the very least it breaks the principle of least surprise and can introduce sneaky bugs.
Of course there are scenarios where maybe you don't need a context. For example, maybe you have a searchable list component that allows complex data as items and need to pass a fnEquals
function so the search can determine whether the search input text matches an item. However, these cases are typically better handled by more composable mechanisms (content projection etc.) which increases reusability.
There is basically no differences
in functionality, but
(i)When you use @input
you get advantage of using @Input
is that we can define the type and whether it is private or public
(ii)As @ConnorsFan
mentioned in the comment, advantage of using @Ouput
is many subscribers can handle the Output event, while only one handler can be supplied for the @Input
property.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With