'Passing @Input Callback or Event Binding with @Output in Angular 13
§ I asked this question yesterday (which I've since realized is confusing, and I'll probably delete it) and having searched further realized it's easier to rephrase as I've done here.
I've searched up the differences§ between passing a callback function via @Input and binding to events emitted via @Output. Most discussion of this seems to be from around the early Angular 2 days, before it was well defined that @Output is the preferred method; and that is understandably true.
In some circumstances, however, the list of desired @Output bindings may not be known by the child component, and instead defined by the parent. For example, a very genericized child component, such as an item-list, which can be used in different contexts with different actions supported. Some contexts (implicitly defined by the parent component) may call for supporting view, edit, and delete actions; others may call for view, save, and share, and so on.
In these cases, the specific @Output bindings (which would otherwise be exposed as (view), (edit), etc.) aren't known by the child component, and would need to be passed in.
With Action and OnAction<TData> defined as:
interface Action {
name: string;
}
interface OnAction<TData> {
name: string;
data: TData;
}
I could pass in a list of supported actions:
@Input() actions: Action[];
And then bind to a generic (onAction):
@Output onAction: EventEmitter<OnAction<any>>;
So that the parent container can pass in the supported actions, and bind to (onAction) which is invoked with the action name and data payload (the item on which the action was taken)
My question is, what are the disadvantages to just passing the functions as a property of the actions I need to support, from parent to child component?
If I were to define an action as:
interface Action<TData> {
name: string;
onAction: (data: TData) => void;
}
And a child component as:
@Component({
selector: "child-component",
template: `
<table>
<tbody>
<tr *ngFor="let item of this.items">
<td>{{item}}</td>
<td>
<button
*ngFor="let action of this.actions"
(click)="action.onAction(item)">
<span>{{action.name}}</span>
</button>
</td>
</tr>
</tbody>
</table>
`
})
export class ListComponent {
@Input() items: any[] = [];
@Input() actions: Action<any>[] = [];
}
Then the parent component need only pass the desired items and actions, and do something meaningful with the onAction callbacks:
@Component({
selector: "parent-component",
template: `
<child-component
[items]="this.items"
[actions]="this.actions">
</child-component>
`
})
export class ParentComponent {
items: any[] = [];
actions: Foo<any>[] = [
{name: "view", onAction: (item: any) => this.handleView(item)},
{name: "edit", onAction: (item: any) => this.handleEdit(item)},
];
private handleView(item: any) { /* ... */ }
private handleEdit(item: any) { /* ... */ }
}
So, as stated above, my question is what are the disadvantages to using @Input-passed callbacks, over binding to @Output
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
