Search⌘ K
AI Features

Passing Data Between Parent/Child Components

Explore how to transfer data between parent and child components in Angular using decorators like @Input for one-way data flow from parent to child, @Output with EventEmitter for child-to-parent communication via events, and @ViewChild for direct child references. Understand when to use each method to maintain clean, flexible component interactions.

There are different ways to pass data in and out of components. Choosing which approach to take depends on the complexity of the application you are developing and the relationship between the components.

The first approach we’re going to look at is the parent/child relationship, where one component has a child component.

Passing data from the parent component to the child component

Using @Input() decorator

The flow of data in this instance is from the parent to the child. We use the @Input() decorator to pass data from the parent to the child component via the template of the child component.

Parent component

For example, look at the following parent component:

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

@Component({
  selector: 'app-parent-comp',
  template: `<app-child-comp [messageForChild]="parentMessage"></app-child-comp>`,
  styleUrls: ['./parent-comp.component.scss']
})
export class ParentCompComponent {
  
  parentMessage = "Tidy your room";
  constructor() { }
}



Here, we are using an inline template, which has the child component’s tag passing the parentMessage property to the child component via the messageForChild property.

Child component

Let’s look at the child component. In this example code you can see that we’ve set the @Input() decorator on the messageForChild property. Now, this property is recognized by Angular as a way to pass properties into the child component.

📝 Note: Press the RUN button to compile and serve the application. Once the app compiles, you can see its output in the Output tab or by clicking on the URL given after Your app can be found at.

import { AppPage } from './app.po';
import { browser, logging } from 'protractor';

describe('workspace-project App', () => {
  let page: AppPage;

  beforeEach(() => {
    page = new AppPage();
  });

  it('should display welcome message', () => {
    page.navigateTo();
    expect(page.getTitleText()).toEqual('Client-Contacts-Manager-Angular app is running!');
  });

  afterEach(async () => {
    // Assert that there are no errors emitted from the browser
    const logs = await browser.manage().logs().get(logging.Type.BROWSER);
    expect(logs).not.toContain(jasmine.objectContaining({
      level: logging.Level.SEVERE,
    } as logging.Entry));
  });
});
Passing data from parent to child component using @Input decorator

You should see the following in the output:

Say Tidy your room

This is a one-way relationship: the parent gets the data, and it can manipulate the data before passing it into the child component. The child component has no way of getting data. That is the job of the parent.

Passing data from the child component to the parent component

@ViewChild() decorator

There are different ways that a child component can pass data to the parent. One way is through using the @ViewChild() decorator. This decorator is used in the parent component to define a property that is a reference to the child component.

Parent component

Using our parent/child components from the previous example, we could add a reference in the ParentComponent like this:

import { Component, ViewChild, AfterViewInit } from "@angular/core";
import { ChildCompComponent } from "../child-comp/child-comp.component";

@Component({
  selector: 'app-parent-comp',
  template: `
  Message: {{ message }}
  <app-child-comp></app-child-comp>`,
  styleUrls: ['./parent-comp.component.scss']
})
export class ParentCompComponent implements AfterViewInit {
  @ViewChild(ChildCompComponent) childComp;
  constructor() {}
  message: string;
  ngAfterViewInit() {
    this.message = this.childComp.message;
  }
}  

Here, we are using the @ViewChild() decorator to set the childComp property as the reference to ChildCompComponent. Thus making it and its public properties available to the parent. Then, in the ngAfterViewInit() life cycle hook, we’re setting the parent’s message property to be the same as the child’s message property.

Child component

Here is our child component:

📝 Note: Press the RUN button to compile and serve the application. Once the app compiles, you can see its output in the Output tab or by clicking on the URL given after Your app can be found at.

import { AppPage } from './app.po';
import { browser, logging } from 'protractor';

describe('workspace-project App', () => {
  let page: AppPage;

  beforeEach(() => {
    page = new AppPage();
  });

  it('should display welcome message', () => {
    page.navigateTo();
    expect(page.getTitleText()).toEqual('Client-Contacts-Manager-Angular app is running!');
  });

  afterEach(async () => {
    // Assert that there are no errors emitted from the browser
    const logs = await browser.manage().logs().get(logging.Type.BROWSER);
    expect(logs).not.toContain(jasmine.objectContaining({
      level: logging.Level.SEVERE,
    } as logging.Entry));
  });
});
Passing data from the child component to the parent component using @ViewChild decorator

You should see the following in the output:

Message: I don't want to tidy my room

Using @Output decorator and EventEmitter class

The second way data can be passed from the child component to the parent is by using the @Output() decorator and the EventEmitter class. This approach involves defining events that can be subscribed to. The child component defines what events it emits, and the parent listens for these events, which can contain data.

This approach is ideal for when the child component needs to let the parent component know of button clicks or when form fields are changed within the child component.

Parent component

Here’s our parent component:

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

@Component({
  selector: 'app-parent-comp',
  template: `
  <app-child-comp
      (messageEvent)="receiveMessageFromChild($event)">
  </app-child-comp>`,
  styleUrls: ['./parent-comp.component.scss']
})
export class ParentCompComponent {

  constructor() {}
  message: string;
  receiveMessageFromChild($event) {
    this.message = $event;
    console.log (this.message)
  }
}  



In the parent, we’ve created an event handler called receiveMessageFromChild($event), which takes in a $event object. In the template, you can see that when messageEvent from the child is fired, the receiveMessageFromChild($event) handler is fired.

Child component

To create messageEvent in the child component, we’re using the @Output() decorator (the opposite of the @Input() decorator) to define an output, which is sent using EventEmitter. The <string> part of EventEmitter is saying that the message/data being passed in the event should be a type of string. This is another way TypeScript does type checking.

📝 Note: Press the RUN button to compile and serve the application. Once the app compiles, you can see its output in the Output tab or by clicking on the URL given after Your app can be found at.

import { AppPage } from './app.po';
import { browser, logging } from 'protractor';

describe('workspace-project App', () => {
  let page: AppPage;

  beforeEach(() => {
    page = new AppPage();
  });

  it('should display welcome message', () => {
    page.navigateTo();
    expect(page.getTitleText()).toEqual('Client-Contacts-Manager-Angular app is running!');
  });

  afterEach(async () => {
    // Assert that there are no errors emitted from the browser
    const logs = await browser.manage().logs().get(logging.Type.BROWSER);
    expect(logs).not.toContain(jasmine.objectContaining({
      level: logging.Level.SEVERE,
    } as logging.Entry));
  });
});
Passing data from the child component to the parent component using @Output decorator

When the application compiles, you can open the given link to view your application. You should see the Send Message button in the output.

Right-click on the application page, click Inspect, move to the Console tab, click the Send Message button, and the sendMessage() function is called. This emits messageEvent, which the parent is listening for, and you should see the following in the Console output:

I don't want to tidy my room

We can use this method to define other events that the child component emits/sends out. It is up to the other components to register that they are interested in listening for and handling these events.

Which approach is better?

So, out of these two approaches for sending data from child components to parent components, which is better? Well, it depends. The first approach clearly sees that this child component is a child of the parent component; it is referenced within. There is a tighter cohesion between the two.

The second approach, where the child component sends out events that the parent or any other component can listen for, makes the relationship between the components more separated, leading to more flexibility if a codebase needs refactoring. It also leads to more separation of concernsIn computer science, separation of concerns (SoC) is a design principle for separating a computer program into distinct sections so that each section addresses a separate concern.

Using the approach of passing data from parents to child components using the @Input() decorator and data from the child to the parent component using events makes the flow of data in our application one-way data flow.

What really matters is that whatever approach you choose, you have to be consistent throughout the application.