How To Pass Data From Child To Parent – Angular

In this post, we will show how to pass data from child to parent components in Angular. Specifically, from a child component to the parent component.

To do this, we will start from where we left with bindingDown but we changed the name of the app to bindingUp. You don’t need to change the name if you don’t want to!


Have a look at Passing custom Angular property to a child component to see how to create a new Angular application or to get the starting code.

Create A New Child Component

We start by creating a new component called InputBook. We will use this component, to add a title to the list of books called favBooks that we have inside app-component.ts.

Let’s write some simple code to have a basic component:

// input-component.html


<h2>Add a new title</h2>
<div>
  <input type="text" placeholder="Write a title">
  <button>Add Title</button>
</div>
// input-component.ts

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

@Component({
  selector: 'app-input-book',
  templateUrl: './input-book.component.html',
  styleUrls: ['./input-book.component.css'],
})
export class InputBookComponent {
  bookTitle: string = '';
  constructor() {}

  onAddBook() {
    console.log('book in ChildComponent:', this.bookTitle);
  }
}

At this point, this component is not very useful. However, we can add it to app-component.html using the selector <app-input-book></app-input-book>.

Once we do that, we should have something similar to the picture below:

Pass data from child to parent
It is now possible to write some text

Binding A Click Event

Let’s make sure that our component works fine.

We use event binding in our button so that the button listens for and responds to user actions such as mouse clicks.

Angular’s event-binding syntax consists of a target event name within parentheses to the left of an equal sign, and a quoted template statement to the right. In our case, <button (click)="onAddBook()">Add Title</button> the target event is a click event and the template statement is onAddTitle.

We didn’t create onAddTitle yet, but the event binding listens for the button’s click events and calls the component’s onAddTitle() method whenever a click occurs.

Inside input-component.ts we create onAddTitle() method and we log a string whenever a user clicks on the button.

// input-component.ts

...

export class InputBookComponent {
  bookTitle: string = '';
  ...

  onAddBook() {
    console.log('What a click!');
  }
}

Two-way Binding

At this point, we want to take a step forward and store the user’s input into a local variable called bookTitle that we initialized in input-component.ts.

When we use two-way binding syntax we need to import NgModule and FormsModule in app.module.ts, which will eventually look like this:

// app.module.ts

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

import { AppComponent } from './app.component';
import { ListFavoritesComponent } from './list-favorites/list-favorites.component';
import { InputBookComponent } from './input-book/input-book.component';

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

We can then use ngModule in our input element so that we bind the text that the user will write into the input element with our variable bookTitle (in input-component.ts). The Angular documentation says that “Two-way binding gives components in your application a way to share data. Use two-way binding to listen for events and update values simultaneously between parent and child components“.

The input element in input-book.component.html becomes <input type="text" placeholder="Write a title" [(ngModel)]="bookTitle"> .

// input-component.html

<h2>Add a new title</h2>
<div>
  <input type="text" placeholder="Write a title" [(ngModel)]="bookTitle">
  <button (click)="onAddBook()">Add Title</button>
</div>

if you want to log the value in the input element on click, change the onAddTitle method to the following:

onAddTitle() {
    console.log('book in ChildComponent:', this.bookTitle);
  }

Note that since we are using ngModel, the input element listens for events and updates values simultaneously. In other words, the value of bookTitle is updated every time the user types something, regardless that the user clicks on the button.

Pass Data From Child To Parent Component

As in Passing custom Angular property to a child component, there are three key steps to pass data from child to parent in Angular.

1. Prepare the Child component to emit data

InputBook is a child component of AppComponent. In input-component.ts, bookTitle gets the value from the input element and we want to pass that value to AppComponent so we can add the title of the book to the list of books.

Broadly speaking, we want to output data from our child component.

A bit of theory

Once again, the Angular documentation on sending data to a parent component is beneficial: “The @Output() decorator in a child component or directive lets data flow from the child to the parent.” This is exactly what we want.

@Output() marks a property in a child component as a doorway through which data can travel from the child to the parent.

The child component uses the @Output() property to raise an event to notify the parent of the change. To raise an event, an @Output() must have the type of EventEmitter, which is a class in @angular/core that you use to emit custom events”.

This is telling us that we need to use @Ouput and EventEmitter.

  • @Output() is a decorator that marks a class field (that we will name soon) as an output property and supplies configuration metadata. We could indeed pass an optional name to use in templates but we will not use this option now. We need to add @Output() bookTitleCreated in input-book.component.ts, where bookTitleCreated is the class field.
  • EventEmitter emits custom events synchronously or asynchronously. EventEmitter is a generic type that is shown in typescript by using < ... >. In between, we define the type of event data that we are going to emit. In our case, we will use { title: string } because we want to pass data in the form of an object with a key called title of type string. After EventEmitter, we need () to call the constructor of EventEmitter. The code regarding the EventEmitter becomes new EventEmitter<{ title: string }>();

Pass Data From Child To Parent

When we put these together we have that input-component.ts becomes:

// input-component.ts

...

export class InputBookComponent implements OnInit {
  @Output() newBookEvent = new EventEmitter<string>();
  bookTitle: string;
  ...

  onAddBook() {
    console.log(this.bookTitle);
  }
}

We then need to change the code in the onAddTitle() method to emit data. To do so, we call the bookTitleCreated property on which we call the emit() method. We pass the object { title: this.bookTitle } to the emit method which is now making this available in AppComponent.

// input-component.ts

...

export class InputBookComponent implements OnInit {
  @Output() newBookEvent = new EventEmitter<string>();
  bookTitle: string;
  ...

  onAddBook() {
    console.log('book in ChildComponent:', this.bookTitle);
    this.newBookEvent.emit(this.bookTitle);
  }
}

Remember that this is only one way to pass data from child to parent. It has pros and cons.

2. Bind Property in Parent Component template

At this point, InputComponent emits data through an event every time the user clicks on the “Add Title” button. We need to instruct InputComponent selector in app-component.html (i.e. <app-input-book>) to listen to this event and do something with it.

This is not very different than what we discussed above in Binding a click event! Consequently, we will use event binding in the InputComponent selector so that the selector listens for and responds to the event coming from InputComponent. The event binding syntax is the same and it consists of a target event name and a quoted template statement.

// app-component.html

<h1>This is {{title}}</h1>
<h2>My favorite books</h2>
  <ul>
    <app-list-favorites 
      *ngFor="let book of favBooks"
      [bookObject] = "book"
      >
    </app-list-favorites>
  </ul>

<app-input-book (newBookEvent)="addBook($event)"></app-input-book>

The last line in app-component.html has the InputComponent selector in which you can see the event binding. The event we are listening to is bookTitleCreated and once the selector detects that event, it calls onBookAdded() method, passing $event to the method itself.

AppComponent is now aware of the event but we need to create onBookAdded() method in app-component.ts to use the data and add the book to the list of favorite books.

3. Use Property in Parent Component class

In app-component.ts, we add the method onBookAdded() that receives some data in the shape of an object with a key named title and a value of type string.

We concatenate that object to favBook using the contact method.

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  title = 'BindingUp';
  favBooks = [
    { title: 'Principles' },
    { title: 'The Story of Success' },
    { title: 'Extreme Economies' },
  ];

  addBook(newBook: string) {
    const bookObject = { title: newBook };
    this.favBooks = this.favBooks.concat(bookObject);
    console.log('book in AppComponent:', bookObject);
  }
}

Conclusions

The app is now working and in this post, we are passing data from a child component (InputComponent) to the parent component (AppComponent).

In conclusion, using a theoretical approach where AppComponent is the Parent component and InputComponent is the Child component, remember the three steps:

  1. Prepare Child Component to emit data
  2. Bind Property in Parent.html
  3. Use Property in Parent.ts

Next: Pass Data To Child Components