'Generic Events Emitted from Component in Angular ~13
I'm trying to determine if I'm going down an undesirable path with how I'm approaching generic event management in an Angular application.
The question I have is: Is there a more built-in or best-practices-conforming way to achieve the following.
Given a simple type, representing an item:
export interface Item {
name: string;
}
I want to create a very generic item list component, that supports emitting actions dictated by the containing component. I've created an Action type representing the types of actions that can be emitted, and an ActionEvent<TPayload> type representing the emitted action event:
export interface Action {
name: string;
}
export interface ActionEvent<TPayload> {
name: string;
payload: TPayload;
}
The generic item list component is then defined as such:
@Component({
selector: "list-component",
template: `
<table>
<tbody>
<tr *ngFor="let item of this.items">
<td>{{item.name}}</td>
<td>
<button
*ngFor="let action of this.actions"
(click)="this.doAction(action.name, item)">
<span>{{action.name}}</span>
</button>
</td>
</tr>
</tbody>
</table>
`
})
export class ListComponent {
@Input() items: Item[] = [];
@Input() actions: Action[] = [];
@Output() onActionEvent: EventEmitter<ActionEvent<Item>> = new EventEmitter<ActionEvent<Item>>();
doAction(name: string, payload: Item) {
this.onActionEvent.emit({name, payload})
}
}
It takes an @Input of items: Item[] and actions: Actions[]; the items to be displayed, and the supported actions of those items respectively.
It also defines an @Output of EventEmitter<ActionEvent<Item>> to emit events for the items.
The container component then, could be defined as such:
@Component({
selector: "container-component",
template: `
<h1>Items</h1>
<list-component
[items]="this.items"
[actions]="this.actions"
(onActionEvent)="this.handleActionEvent($event)">
</list-component>
`
})
export class ContainerComponent {
items: Item[] = [
{name: "foo"},
{name: "bar"},
{name: "qux"},
];
actions: Action[] = [
{name: "view"},
{name: "edit"},
];
handleActionEvent(actionEvent: ActionEvent<Item>) {
console.log(actionEvent);
}
}
This then resembles something such as:
Now, varying containers can define varying actions; some may support view and edit, others may support different actions. I could easily add a share action (and the corresponding handler code, which could itself be wrapped up in the Action type definition) and have something such as:
Where I'm performing console.log(actionEvent), the container's handler would be responsible for determining what meaningful behavior to perform on view or edit or whatever else.
So, as stated at the top, am I painting myself into an undesirable corner with this approach? I'm trying to stay very DRY, but I feel like I'm straying away from KISS. Additionally, I'm as yet unaware of a built-in or more best-practices-conforming way to accomplish this.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|


