Propagating events from nested components – Components and Pages
We will add the options to delete an item from the list and increase the number of repetitions to our diary. First, let’s add the buttons to the list item template. In the entry-item.component.html file, we will edit the template:
Date: {{ exerciseSet.date | date }}
Exercise: {{ exerciseSet.exercise }}
Sets: {{ exerciseSet.sets }}
Reps: {{ exerciseSet.reps }} Delete New Rep
The challenge here is to ensure that the action that will happen on each item in the list if correctly identified to be applied correctly – that is, the Diary Smart component that handles the list will find the corresponding item and change it.
For this, we will apply the Angular output feature to the item component:
@Output() newRepEvent = new EventEmitter();
@Output() deleteEvent = new EventEmitter();
delete() {
this.deleteEvent.emit(this.exerciseSet.id);
}
newRep() {
const reps = ++this.exerciseSet.reps;
const newItem: ExerciseSet = {
…this.exerciseSet,
reps,
};
this.newRepEvent.emit(newItem);
}
We create two outputs, each one for a different event that we want to emit, and we type them because we need different actions.
We then create the delete method, which will emit the id value of the item we want to delete, and the newRep method, with which we will add repetitions to the item of the exercise that will be performed and emit that item.
We will return to the template to associate the methods with the buttons created:
<button
class=”mr-2 rounded bg-red-500 py-2 px-4 font-bold text-white hover:bg-red-700″
(click)=”delete()”
>
Delete
<button
class=”rounded bg-blue-500 py-2 px-4 font-bold text-white hover:bg-blue-700″
(click)=”newRep()”
>
New Rep
Now let’s change the list-entries.component presentation component for creating the output, which here, for simplicity, will have the same name as the item’s output:
export class ListEntriesComponent {
@Input() exerciseList!: ExerciseSetList;
@Output() newRepEvent = new EventEmitter();
@Output() deleteEvent = new EventEmitter();
.
.
.
}
To propagate the item’s events, we will change the list template:
<app-entry-item
[exercise-set]=”item”
(deleteEvent)=”deleteEvent.emit($event)”
(newRepEvent)="newRepEvent.emit($event)"
/>
We can see that we only emit the item’s event using the emit method of the outputs.
Finally, we will refactor the DiaryComponent Smart component to react to the item’s event. First, let’s see the template:
.
.
.
As in the previous example, we used parentheses to associate it with a method, which will handle the event and receive the element emitted by the parameter of that method using the $event variable.
We will now refactor the component by creating two new methods – one to delete a journal entry and one to create a new repetition for an exercise:
.
.
.
deleteItem(id: string) {
this.exerciseList = this.exerciseList.filter((item) => item.id !== id);
}
newRep(exerciseSet: ExerciseSet) {
const id = exerciseSet.id;
const i = this.exerciseList.findIndex((item) => item.id === id);
if (i >= 0) {
this.exerciseList[i] = { …exerciseSet };
}
}
.
.
.
We are using the TypeScript array methods to simulate deleting and changing the array of items. We can see that the method already receives the deletion item or id automatically due to Angular’s event emission mechanism.
We are taking advantage of the smart and presentation component pattern here to leverage its usage with a slightly more complex requirement.
Summary
In this chapter, we studied the elements responsible for rendering the interface of our project, the components. We saw how to create and organize the components in a granular way, resulting in our project being more maintainable.
We also studied how to communicate between components using the @Input and @Output attributes, using the capabilities of Angular that facilitate this communication.
We saw the good practice of using TrackBy to iterate lists in templates using the ngFor directive, improving performance specifically for lists with many items.
Finally, we study the design pattern of the Smart and Presentation components, a way of organizing components and their interactions in order to simplify this orchestration with a unidirectional information flow.
In the next chapter, we will study the Angular elements responsible for the business rules and interaction with the backend – the services.