Input and Output are two decorators in Angular responsible for communication between two components.
In this post, we’ll look into how to pass the data to the components using @Input
and to get the data back flowing with @Output
.
As I mentioned above, @Input
and @Output
are decorators. So what is a decorator?
Decorator
A decorator is a function that is invoked with @
prefix and followed by class, method, property.
Ex:
@Input()
description: string;
How to Pass Data?
Before we proceed to start coding the Input and Output decorators, let's see how to pass the data to any component.
Think that we have two components parent
and child
. The selector for the child is say child-comp
. Now, if we are in parent component, we’ll just add an attribute to the tag inside of parent’s template.
import { Component } from '@angular/core'
@Component({
selector: 'my-app',
template: `
<child-comp [parentCount]="count"></child-comp>
`
})
export class App {
count: number = 10;
}
So, parentCount
is the @Input
binding for the child element and fullName
is the local component’s property, which has data.
@Input
The @Input
decorator is for obtaining the data that is passed from a component.
Let’s continue with the above example. Now, we have the data that is coming in from the parent, we’ve to capture the data in the child component using @Input
.
All we have to do is add a variable with the name as parentCount
and use it to bind the element in the template
Ex: @Input() parentCount: number;
So, the child component will look like this.
import { Component, Input } from '@angular/core';
@Component({
selector: 'child-comp',
template: `
<div>
{{ parentCount }}
</div>
`
})
export class ChildComponent {
@Input()
parentCount: number;
}
Do not forget to add our child component to declarations section of the @NgModule
.
Aliasing in @Input
We can alias the data that is coming from the component. As in the example above, we could have aliased parentCount
like this:
@Input(‘parentCount‘) count: number
Now, we’ll have the data in count
variable. Basically, if we have the same variable names that might conflict in the child component, we could alias to a different name.
@Output
So far, we’ve just seen passing data in one-way direction, i.e., from parent component to child component. Now, let’s see how to make a stateful connection between parent and child.
@Output
is not just a single thing that can pass data back from child to parent. We have to use EventEmitter
to emit the event to the parent so that parent can capture the exposed event and retrieve data.
We’ve to combine @Input
decorator to pass the initial data to the child component and get back the updated data using @Output
decorator and Event emitter.
Let’s extend the functionality of the above @Input
decorator to push back the updated content to parent and display the updated value in the parent component.
import {Component, Input, Output, EventEmitter} from '@angular/core'
@Output()
change: EventEmitter<number> = new EventEmitter<number>();
this.change.emit(11);
In the above code, we need to import Input, Output, EventEmitter to do the push from child to parent.
We have declared a change event which is of type EventEmitter
which pushes a number type of data. Note that change is just an event that we give for the event emitter. It is neither a convention nor a keyword. You can have any custom name as well. I’d encourage you to change the change
event name to any custom name in the demo code and make sure it is working.
The event emitter will have emit()
method to emit to the parent. Call the last line whenever the parent should be notified of that change.
import {Component} from '@angular/core'
import {ChildComponent} from 'src/child.component'
@Component({
selector: 'parent',
template: `
<child-comp
[parentCount]="count"
(change)="updateFromChild($event)"></child-comp>
`
});
export class ParentComponent {
count: number = 0;
updateFromChild($event){
this.count++;
}
}
So, for the parent, we will just add that EventEmitter
’s event to the child component selector here (it is child-comp
). As you can see, I’ve added (change)
event to the tag and given a method that can receive when the event is emitted.
The $event
parameter on the updateFromChild
method will have the content that is sent from the component that emitted the event.
Though this is just for passing data back and forth between parent and child, it takes quite a bit of setup to achieve it. But once habituated, this looks pretty simple and easy thing to do in Angular.