Let's get to the point. Angular document gives me a basic understanding of each feature, but when it come to solving real world problem, I would be thinking of how do they work together?.
I've written one example to demonstrate just that.
Problem Scenario
In one course, I have to learn two subjects. Angular and Code Sandbox. In Angular subject I have two tasks which give me two credit. Code sandbox has one task with one credit.
To complete the course, I need to gain three credits.
Now I need to write an application to track my progress.
Big Picture
+--------------------+
| Subjects | : Keeping record of credits
| +--------------+ |
| | Tasks | | : To do list, tick off done tasks
| | +---------+ | |
| | | Report | | | : Keeping record of task completed
| | +---------+ | |
| +--------------+ |
+--------------------+
Abstract Steps
- Initialise Default Angular Project
- Create three components (subjects, tasks, report)
- Replace content of
app.comopnent.html
withsubjects
component - Add functions
Codes
This diagram let you visualise where @Input
, @Output
and EventEmitter
is used
+----------+ Data Flow +-----------+
| Tasks + ----------> + Subjects |
+----------+ +-----------+
@Output():EventEmitter
+----------+ Data Flow +----------+
| Tasks + ----------> + Report |
+----------+ +----------+
@Input():number
Subject Component
<section id="subjects">
<h4>Subjects</h4>
<div *ngFor="let subject of subjects">
<div>{{subject.desc}} - Credit: {{subject.credit}}</div>
</div>
<app-task
(subjectCompleteEvent)="receiveSubjectCompletion($event)"
></app-task>
</section>
import { Component, OnInit } from "@angular/core";
@Component({
selector: "app-subject",
templateUrl: "./subject.component.html"
})
export class SubjectComponent implements OnInit {
subjects: any[] = [];
ngOnInit(): void {
this.subjects.push({ code: "ng", desc: "Angular", credit: 0 });
this.subjects.push({ code: "sb", desc: "Code Sanbox", credit: 0 });
}
receiveSubjectCompletion(subjectComplete: any) {
const index = this.subjects
.map((subject) => {
return subject.code;
})
.indexOf(subjectComplete.code);
subjectComplete.credit
? this.subjects[index].credit++
: this.subjects[index].credit--;
}
}
Tasks Component
<section id="tasks">
<h4>Tasks</h4>
<div *ngFor="let task of todos">
<input
type="checkbox"
(change)="onCheck($event)"
value="{{task.code}}"
/>{{task.desc}}
</div>
<app-report [completed]="taskCompleteCounts"></app-report>
</section>
import { Component, OnInit, Output, EventEmitter } from "@angular/core";
@Component({
selector: "app-task",
templateUrl: "./task.component.html"
})
export class TaskComponent implements OnInit {
// define output type for notifying parent component
@Output() subjectCompleteEvent: EventEmitter<any> = new EventEmitter<any>();
// input value for report (child)
taskCompleteCounts = 0;
todos: any[] = [];
ngOnInit(): void {
this.todos.push({ code: "ng", desc: "Scaffold Angular Project" });
this.todos.push({ code: "ng", desc: "Try EventEmitter, @Input, @Output" });
this.todos.push({ code: "sb", desc: "Try Code Sandbox" });
}
onCheck(event: any) {
if (event.target.checked) {
// update value for child
this.taskCompleteCounts++;
// notify parent
this.subjectCompleteEvent.emit({
code: event.target.value,
credit: true
});
} else {
this.taskCompleteCounts--;
this.subjectCompleteEvent.emit({
code: event.target.value,
credit: false
});
}
}
}
Report Component
<section id="report">
<h4>Report</h4>
<div>
Task completed: {{completed}}
</div>
</section>
import { Component, OnInit, Input } from "@angular/core";
@Component({
selector: "app-report",
templateUrl: "./report.component.html"
})
export class ReportComponent implements OnInit {
// define input type. value will be updated from parent
@Input() completed: number;
ngOnInit(): void {}
}
Demo
https://codesandbox.io/s/ng-eventemitter-input-output-57r1z
It's freedom to use this content under CC-BY-4.0, program codes under CC0 licence.
Top comments (0)