Angular is based on components and components have to communicate with each other. when we nesting components, we create a parent – child relationship and the most basic communication between parent and child components are property binding and event binding. with the property and event binding we can send data into the component and receive data from the component.
In my previous articles, we learned how we can use this bindings on html element and how to use this bindings on directives. now lets learn how to use this bindings on components.
a small side note: keep in my mind that there are many ways to communicate between components (not specific to child-component relationship). we can communicate with the router, service, subject and a state management (NgRx).
Custom Property Binding
When we using property binding on html elements, we bind to the native property (attribute) of the html element we currently using like: disables, src and such.
when we want to receive data from parent component to child component, we need to create a custom property for property binding. we create this custom property with the @Input decorator on the child component.
import { Component } from "@angular/core";
@Component({
selector: "parent",
template: `<child [myName]="name"></child>`,
styles: []
})
export class ParentComponent {
name: string = "Alex";
}
import { Component, Input } from "@angular/core";
@Component({
selector: "child",
template: `<h1>Hello {{ myName }}</h1>`,
styles: []
})
export class ChildComponent {
@Input() myName: string;
}
sometimes you don’t want to use the same property name outside of the component as you use inside of it. to achieve that we have to use an alias to the custom property.
import { Component } from "@angular/core";
@Component({
selector: "parent",
template: `<child [name]="name"></child>`,
styles: []
})
export class ParentComponent {
name: string = "Alex";
}
import { Component, Input } from "@angular/core";
@Component({
selector: "child",
template: `<h1>Hello {{ myName }}</h1>`,
styles: []
})
export class ChildComponent {
@Input('name') myName: string;
}
Custom Event Binding
When we using event binding on html elements, we bind to the native event of the html element we currently using like: submit, click keyup and such.
when we want to send data from child component to parent component, we need to create a custom event for event binding. we create this custom event with the @Output decorator on the child component.
import { Component } from "@angular/core";
@Component({
selector: "parent",
template: `<child (buttonClickedEvent)="onButtonClicked()"></child>`,
styles: []
})
export class ParentComponent {
onButtonClicked(): void {
alert("Hey, someone clicked the button in the child component");
}
}
import { Component, EventEmitter, Output } from "@angular/core";
@Component({
selector: "child",
template: `<button (click)="doSomething()">Click Me</button>`,
styles: []
})
export class ChildComponent {
@Output() buttonClickedEvent: EventEmitter = new EventEmitter();
doSomething(): void {
this.buttonClickedEvent.emit();
}
}
sometimes you don’t want to use the same event name outside of the component as you use inside of it. to achieve that we have to use an alias to the custom event.
import { Component } from "@angular/core";
@Component({
selector: "parent",
template: `<child (eventFired)="onButtonClicked()"></child>`,
styles: []
})
export class ParentComponent {
onButtonClicked(): void {
alert("Hey, someone clicked the button in the child component");
}
}
import { Component, EventEmitter, Output } from "@angular/core";
@Component({
selector: "child",
template: `<button (click)="doSomething()">Click Me</button>`,
styles: []
})
export class ChildComponent {
@Output('eventFired') buttonClickedEvent: EventEmitter = new EventEmitter();
doSomething(): void {
this.buttonClickedEvent.emit();
}
}
Except notify outside that something happen in the child component, we can also pass data outside the child component by passing the data when we emit an event
import { Component } from "@angular/core";
@Component({
selector: "parent",
template: `<child (sendDatadEvent)="showData($event)"></child>`,
styles: []
})
export class ParentComponent {
showData(data: { name: string; message: string }): void {
console.log(data.name, data.message);
}
}
import { Component, EventEmitter, Output } from "@angular/core";
@Component({
selector: "child",
template: `<button (click)="sendDataOutside()">Click Me</button>`,
styles: []
})
export class ChildComponent {
@Output() sendDatadEvent: EventEmitter<{name: string;message: string;}> = new EventEmitter<{
name: string;
message: string;
}>();
sendDataOutside(): void {
this.sendDatadEvent.emit({ name: "Joe", message: "Hi All" });
}
}