Components are the essential building block of Angular. @Component decorator is used to decorate any entity as a component, of which there are two kinds - stateful and stateless. A stateful component can store and change data in regards to the part state, it monitors all progressions and reflects individual changes to related components. A stateless part doesn’t monitor state changes, it ascertains inside, and never straightforwardly reflects changes across related components. Presently we have the fundamental information about Angular components and are prepared to explore how to pass information from child component to parent component.
We use EventEmitter API and @Output decorator to transfer or notify any parent component via events that something has changed or we wish to change it.
Firstly, we need to make an event listener within the parent component that listens for when a value changes inside our child component via output binding of EventEmitter to pass/emit events from one component to another (generally from child to parent). This custom output binding is formed by using the @Output() decorator. For better understanding, we’ll use the stateful component that keeps track of the counter named CounterComponent.
First of all, we create our new component,
ng generate component counter
And then register our new CounterComponent in @NgModule (in app.module.ts file) that allows us to use it inside our components registered in @NgModule.
Now in AppComponent, we can add CounterComponent as a custom element inside the template -
app.component.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import {
Component
} from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: `
<div class="app">
<app-counter></app-counter>
</div>
`,
})
export class AppComponent {
initial_value: number = 0;
}
When we do not use the built-in properties and want to create custom ones then we have to tell Angular the name of the property binding. So, let’s set a property binding named count on our component and supply the value of initial_value (which can be any number, in our case, it’s 0) and handleCounterChange($event) function is passed to (change) event binding through which we will catch events further.
app.component.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import {
Component
} from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: `
<div class="app">
<app-counter
[count]="initial_value"
(change)="handleCounterChange($event)" >
</app-counter>
</div>
`,
})
export class AppComponent {
initial_value: number = 0;
handleCounterChange(event) {
}
}
Whenever we want changes that occurred in the child component (CounterComponent) to reflect on the parent component (AppComponent), we need to call the handleCounterChanges() function. Now we’re going to bind that function to EventEmitter in the child component. Through that we emit each change of counter in the form of events and then we will catch it in the parent component and finally handle that event by using the handleCounterChanges() function.
counter.component.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import {
Component,
Input,
OnInit,
Output,
EventEmitter
} from '@angular/core';
@Component({
selector: 'app-counter',
templateUrl: './counter.component.html',
styleUrls: ['./counter.component.css']
})
export class CounterComponent implements OnInit {
@Input()
count: number = 0;
@Output()
change = new EventEmitter()
ngOnInit(): void {}
}
An interesting fact about EventEmitter is that we can also define the type of event we are emitting. In our case we are emitting a number type, so the syntax defining EventEmitter can also be written as -
counter.component.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import {
Component,
Input,
OnInit,
Output,
EventEmitter
} from '@angular/core';
@Component({
selector: 'app-counter',
templateUrl: './counter.component.html',
styleUrls: ['./counter.component.css']
})
export class CounterComponent implements OnInit {
@Input()
count: number = 0;
@Output()
change: EventEmitter < number > = new EventEmitter < number > ();
ngOnInit(): void {}
}
Until now we have created a change property and bound an instance of EventEmitter to it. Now to reflect changes from child to parent we just have to call this**.change** method. .As it references an instance of EventEmitter, we have to invoke EventEmitter to emit an event by using the .emit() method.
counter.component.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import {
Component,
Input,
OnInit,
Output,
EventEmitter
} from '@angular/core';
@Component({
selector: 'app-counter',
templateUrl: './counter.component.html',
styleUrls: ['./counter.component.css']
})
export class CounterComponent implements OnInit {
@Input()
count: number = 0;
@Output()
change: EventEmitter < number > = new EventEmitter < number > ();
incrementCounter() {
this.count++;
this.change.emit(this.count)
}
decrementCounter() {
this.count--;
this.change.emit(this.count)
}
ngOnInit(): void {}
}
This will emit an event that will be caught by (change) listener in the parent component and pass an instance of that event (event property) $event as an argument of the method we assigned for that listener, i.e., handleCounterChanges($event). This function will be invoked every time a new event is emitted and listened to by (change).
So finally, we update the value of initial_count based on event listened -
app.component.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import {
Component
} from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: `
<div class="app">
<app-counter
[count]="initial_value"
(change)="handleCounterChange($event)" >
</app-counter>
</div>`,
})
export class AppComponent {
initial_value: number = 0;
handleCounterChange(event) {
this.initial_value = event
}
}