Learn about Input, Output and View Queries—essential APIs for passing data, raising events and retrieving child components or DOM elements in Angular.
Angular, a versatile framework for building dynamic web applications, offers developers various tools for managing component interactions and DOM manipulation. Previously, we discussed Angular’s Signals API and its role in state management. In this article, we’ll cover some other component communication essentials—Input, Output and View Queries—essential APIs for passing data, raising events and retrieving child components or DOM elements.
The code examples in this article are adapted from the official Angular documentation, with expansions and explanations added where applicable. Let’s dive in!
In Angular, components are the building blocks of your application. You’ll often want to pass data from a parent to a child component. This is where Input Properties (i.e., sometimes known as Signal Inputs) come into play. Input properties allow a parent component to bind values to a child component’s properties, facilitating data flow into the child component.
We use the input()
function from @angular/core
to declare an input property. This function creates a signal that holds the value passed from the parent component.
import { Component, input } from '@angular/core';
@Component({/*...*/})
export class CustomSliderComponent {
value = input(0);
}
In the above example, the value
property of CustomSliderComponent
is an input that can receive data from a parent component. We initialize it with a default value of 0.
Input properties are signals, so we read their values by calling them as functions. As a result, the value()
function can be used in the template to display the current value.
import { Component, input } from '@angular/core';
@Component({
selector: 'app-custom-slider',
template: `
<div>
<p>Value: {{ value() }}</p>
</div>
`,
})
export class CustomSliderComponent {
value = input(0);
}
To pass data to the CustomSliderComponent
, we bind to its input property in the parent component’s template as follows:
<app-custom-slider [value]="50"></app-custom-slider>
Here, we’re setting the value
input of CustomSliderComponent
to 50
.
For a great read on the difference between traditional Input decorators and input signals, check out the article we’ve written before on Why Move to Input Signals—Bye, @Input() 👋.
While input properties allow data to flow into a component, Output Events enable components to emit events to their parent components. This is essential for communication from child components back to parents, especially when user interactions occur.
To define an output event, we can use the output()
function from @angular/core
:
import { Component, output } from '@angular/core';
@Component({
selector: 'app-expandable-panel',
template: `
<div>
<button (click)="closePanel()">Close Panel</button>
</div>
`,
})
export class ExpandablePanelComponent {
panelClosed = output<void>();
closePanel() {
this.panelClosed.emit();
}
}
In the above example, panelClosed
is an output event that emits when the panel is closed, and the emit()
method is used to trigger the event. Parent components can then listen to output events using event binding syntax:
<app-expandable-panel (panelClosed)="onPanelClosed()"></app-expandable-panel>
In the parent component’s TypeScript file, we then define the onPanelClosed()
method to handle the event.
onPanelClosed() {
console.log('Panel was closed. Event was emitted.');
}
Output events can also emit data. Below is a simple example of emitting numeric data from the child component.
import { Component, output } from '@angular/core';
@Component({
selector: 'app-value-changer',
template: `
<button (click)="changeValue()">Change Value</button>
`,
})
export class ValueChangerComponent {
valueChanged = output<number>();
changeValue() {
this.valueChanged.emit(42);
}
}
Parent components can then access the emitted data using the $event
variable:
<app-value-changer (valueChanged)="onValueChanged($event)"></app-value-changer>
onValueChanged(newValue: number) {
console.log(`New value is ${newValue}`);
}
View Queries can access elements, directives or child components within a component’s template. They are particularly useful when interacting with or manipulating child elements directly.
To query for a single element or component, we can use the viewChild()
function:
import { Component, viewChild } from '@angular/core';
@Component({
selector: 'app-custom-card-header',
template: `<h1>{{ title }}</h1>`,
})
export class CustomCardHeader {
title = 'Header Title';
}
@Component({
selector: 'app-custom-card',
template: `<app-custom-card-header></app-custom-card-header>`,
})
export class CustomCard {
header = viewChild(CustomCardHeader);
getHeaderTitle() {
return this.header()?.title; // 'Header Title'
}
}
In the above code example, the viewChild()
function references the CustomCardHeader
component and access its title
property.
If we have multiple instances and want to query all of them, we can use the viewChildren()
function:
@Component({
selector: 'app-custom-action',
template: `<button>{{ label }}</button>`,
})
export class CustomAction {
label = 'Action';
}
@Component({
selector: 'app-custom-card',
template: `
<app-custom-action label="Save"></app-custom-action>
<app-custom-action label="Cancel"></app-custom-action>
`,
})
export class CustomCard {
actions = viewChildren(CustomAction);
getActionLabels() {
return this.actions().map(action => action.label);
}
}
In this example, the viewChildren()
function queries all instances of the CustomAction
component and retrieve their labels.
While view queries access elements within a component’s own template, Content Queries allow a component to access projected content—elements or components passed into it from the parent component. You can read more about content queries in the following documentation—Referencing component children with queries | Content queries.
Understanding Input Properties, Output Events and View Queries is essential for effective component communication in Angular applications. Inputs allow data to flow into components, outputs enable components to emit events to parent components, and view queries provide a way to access and interact with child elements or components within a component’s own template.
By leveraging these features, we can create rich, interactive, well-structured Angular applications promoting clean component architecture and seamless data flow. For more information on these topics, be sure to check out the following resources:
Hassan is a senior frontend engineer and has helped build large production applications at-scale at organizations like Doordash, Instacart and Shopify. Hassan is also a published author and course instructor where he’s helped thousands of students learn in-depth frontend engineering skills like React, Vue, TypeScript, and GraphQL.