Angular: Sharing Data Between Components With @Input @Output

Afif Alfiano
8 min readFeb 26, 2023

--

In modern web apps, one of the requirements is sharing data between components.

https://unsplash.com/photos/taiuG8CPKAQ
https://unsplash.com/photos/taiuG8CPKAQ

In modern web apps like single-page applications. We should share data between components to make the application real-time without hard refresh. For example: If we have a components cart and product then the user clicks on the button add to cart on the component product, it should increase counting on the component cart.

In this case, we will talk about @Input and @Output in Angular. The function of @Input is to share data from parent to child. It is called the top-bottom sharing of data. Then, function @Output is to share data from child to parent. It is called the bottom-top sharing of data. You can read more about this thing here

Setup

Make sure you have initiated the project angular and are ready to use. First of all, we need to import the forms module in app.module.ts because in this project we will use ngModel two-way data binding from the forms module.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
FormsModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

After that, create component parent and child.

ng generate component parent && ng generate component child

Then, update file app.component.html

<app-parent></app-parent> 

After that, update the file parent.component.html to call the child component.

<div class="container">
<p>parent works!</p>
<app-child></app-child>
</div>

After that, update the file child.component.html

<div class="container">
<p>child works!</p>
</div>

The project is not fancy, just focuses on the concept of @Input and @Output . The project looks like this

So, the child component is inside the parent component. The outline color is to identify an area of the component. The red color is for the parent component and the green color is for the child component.

Input

Next, we add a property to sharing data from parent to child and the code will be like this.

<div class="container">
<p>parent works!</p>
<input type="text" [(ngModel)]="name">
<app-child [name]="name"></app-child>
</div>

We pass data [name] from the variable name on the parent component. We use two-way data binding input text with [(ngModel)] to understand the changes of state on the variable name.

Also, we need to update parent.component.ts

import { Component } from '@angular/core';

@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.scss']
})
export class ParentComponent {
name = 'Unknown';
}

The variable name has a default value Unknown.

After that, the child component will be like this.

<div class="container">
<p>child works!</p>
<p>My name is {{name}}</p>
</div>

Also, we need to update child.component.ts

import { Component, Input } from '@angular/core';

@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.scss']
})
export class ChildComponent {
@Input() name!: string;
}

The @Input is to get data from a parent component through the variable name. The project looks like this.

Demo

See the image below about @Input

Input

Output

Then, we need to pass data from child to parent. We can use @Output and EventEmitter.

Update file parent.component.html

<div class="container">
<p>parent works!</p>
<input type="text" [(ngModel)]="name">
<app-child [name]="name" (childToParent)="getDataChild($event)"></app-child>
<p>Data from child: {{child}}</p>
</div>

We need to add (childToParent)=”getDataChild($event)” on component app-child because from the child to pass the data need to @Output with the symbol (nameOutput), and we get the data from the parent component with the function getDataChild($event). To make sure the value is received, we put some element p to show the value of the child.

Also parent.component.ts

import { Component } from '@angular/core';

@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.scss']
})
export class ParentComponent {
name = 'Unknown';
child!: string;

getDataChild($event: string) {
this.child = $event;
}
}

getDataChild is a function to get value from the child component where the parameter $event is the data. After that, we assign the $event to the local variable which means the variable child.

The difference @Input and @Output on the component is @Input using the symbol [nameInput] to pass value, while the @Output using the symbol (nameOutput) to pass value.

After that, we need to update child.component.html

<div class="container">
<p>child works!</p>
<p>Data from parent: {{name}}</p>
<input type="text" [(ngModel)]="feedback" (keyup)="onSendFeedback(feedback)">
</div>

We add element input text with two-way data binding to send the data or emit data from the child. In that element, we put the function onSendFeedback at the event keyup to pass the feedback value.

Also, update child.component.ts

import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.scss']
})
export class ChildComponent {
@Input() name!: string;
feedback = '';
@Output() childToParent: EventEmitter<string> = new EventEmitter<string>();

onSendFeedback(feedback: string) {
this.childToParent.emit(feedback);
}
}

To pass data from child to parent we use @Output and EventEmitter. So, on the function onSendFeedback we pass the value feedback with emit data on the variable childToParent.

Output

So, the project will be like this.

Demo Output

Sharing Data Between Sibling Components

Maybe, In another case, we want to share data between component A and component B on the same page or container component. Look at the image below.

Sibling Component

First, generate component container, sibling one and sibling two.

ng g c container && ng g c sibling-one && ng g c sibling-two

The structure project is like this.

Structure Component

After that, update app.component.html

<app-parent></app-parent>
<app-container></app-container>

We put the app-container in app.component.html, so it will be rendered in the sample route.

Then, update the file container.component.html

<h1>Sharing Data Between Sibling Component</h1>
<div class="container">
<p>container works!</p>
<app-sibling-one></app-sibling-one>
<app-sibling-two></app-sibling-two>
</div>

The project will be like this

Demo Sharing Data

The purpose is how to share data between component sibling one and component sibling two on the same page or container component. So, we need to update sibling-one.component.html

<div class="container">
<p>sibling-one works!</p>
<p>Data from sibling two: {{fromDataSiblingTwo}}</p>
<button type="button" (click)="sendToSiblingTwo()">Send Data to Sibling Two</button>
<p>New Data Received: {{newDataFromSiblingTwo}}</p>
</div>
  • fromDataSiblingTwo is a variable to show the current state data from outside.
  • A button with the function sendToSiblingTwo() is a button to trigger send data to go to an outside component.
  • newDataFromSiblingTwo is a variable to show the current state data after an action click from component sibling two.

After that, update sibling-one.component.ts

import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
selector: 'app-sibling-one',
templateUrl: './sibling-one.component.html',
styleUrls: ['./sibling-one.component.scss']
})
export class SiblingOneComponent {
@Input() fromDataSiblingTwo!: string;
@Output() sendDataToSiblingTwo: EventEmitter<string> = new EventEmitter();
@Input() newDataFromSiblingTwo!: string;
sendToSiblingTwo() {
this.sendDataToSiblingTwo.emit('Good by sibling two');
}
}
  • fromDataSiblingTwo is a variable to get data from the container component.
  • sendDataToSiblingTwo is a variable to pass data go outside the component (in this case for sibling two)
  • newDataFromSiblingTwo is a variable to get data after the action click the button from component sibling two.
  • Function sendToSibilingTwo() is a function to trigger emit data. So the output sendDataToSbilingTwo doesn’t have value if we don’t set the value with emit.

Next, update sibling-two.component.html

<div class="container">
<p>sibling-two works!</p>
<p>Data from sibling one: {{fromDataSiblingOne}}</p>
<button type="button" (click)="sendToSiblingOne()">Send Data to Sibling One</button>
<p>New Data Received: {{newDataFromSiblingOne}}</p>
</div>

The explanation is the same with a component sibling one.

After that, update sibling-two.component.ts

import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
selector: 'app-sibling-two',
templateUrl: './sibling-two.component.html',
styleUrls: ['./sibling-two.component.scss']
})
export class SiblingTwoComponent {
@Input() fromDataSiblingOne!: string;
@Output() sendDataToSiblingOne: EventEmitter<string> = new EventEmitter<string>();
@Input() newDataFromSiblingOne!: string;

sendToSiblingOne() {
this.sendDataToSiblingOne.emit('Good by sibling one');
}

}

The explanation is the same with a component sibling one.

After the sibling-one component and sibling-two component are already done. Next, we need to update the container component.

<h1>Sharing Data Between Sibling Component</h1>
<div class="container">
<p>container works!</p>
<app-sibling-one [fromDataSiblingTwo]="fromDataSiblingTwo"
[newDataFromSiblingTwo]="newDataFromSiblingTwo"
(sendDataToSiblingTwo)="getDataSiblingOne($event)"></app-sibling-one>

<app-sibling-two [fromDataSiblingOne]="fromDataSiblingOne"
[newDataFromSiblingOne]="newDataFromSiblingOne"
(sendDataToSiblingOne)="getDataSiblingTwo($event)"></app-sibling-two>
</div>
  • fromDataSiblingTwo, newDataFromSiblingTwo is Input to pass data from the container component to sibling one.
  • sendDataToSiblingTwo is the output that we will get the value after the action click the button on component sibling one and we will get the data from the function getDataSiblingOne($event).
  • fromDataSiblingOne, newDataFromSiblingOne is Input to pass data from the container component to sibling two.
  • sendDataToSiblingOne is the output that we will get the value after the action click the button on component sibling two and we will get the data from the function getDataSiblingTwo($event).

Also the container.component.ts

import { Component } from '@angular/core';

@Component({
selector: 'app-container',
templateUrl: './container.component.html',
styleUrls: ['./container.component.scss']
})
export class ContainerComponent {
fromDataSiblingOne = 'Hello Number Two';
fromDataSiblingTwo = 'Hello Number One';

newDataFromSiblingOne = '';
newDataFromSiblingTwo = '';

getDataSiblingOne($event: any) {
this.newDataFromSiblingOne = $event;
}

getDataSiblingTwo($event: any) {
this.newDataFromSiblingTwo = $event;
}
}
  • The variables fromDataSiblingOne and fromDataSiblingTwo have a default value.
  • The variables newDataFromSiblingOne and newDataFromSiblingTwo is variable that will have value if the user clicks the button on component sibling one or sibling two.
  • getDataSibilingOne is a function to get data from component sibling one after the user clicks the button to trigger or emit the value.
  • getDataSiblingTwo is a function to get data from component sibling two after the user clicks the button to trigger or emit the value.

The project will be like this.

Demo Input Output

Lastly, we already completed this tutorial. Hopefully, this article is useful for you guys. If any feedback or input for me, just give it to me and I will fix it for the next tutorial.

I have pushed this project in my GitHub repository on branch communication-data-input-output, you can check in this link below.

Thank you for taking the time to read this article.

--

--

No responses yet