Angular 19 Signals with input()
and output()
With Angular 16+, the Composition API offers a modern and reactive way to manage component state using signal()
, input()
, and output()
. In Angular 19, this approach is more powerful than ever, enabling lightweight and reactive component communication.
In this guide, we'll build a Product Dashboard using:
-
input()
andoutput()
for reactive component I/O -
signal()
for local state management - Standalone components with full signal-based communication
Folder Structure
/components
├── product-page/
│ └── product-page.component.ts
├── product-add/
│ └── product-add.component.ts
├── product-list/
│ └── product-list.component.ts
1. product-add.component.ts
– Emits new product using output()
import { Component, output, signal } from '@angular/core';
export interface Product {
id: number; name: string; price: number;
}
@Component({
selector: 'product-add',
standalone: true,
template: `
Add Product
Add
`,
})
export class ProductAddComponent {
name = signal('');
price = signal(0);
productAdded = output<Product>();
addProduct() {
if (!this.name || this.price() <= 0) {
return;
}
const productAdded: Product = {
id: Math.floor(Math.random() * 1000),
name: this.name(),
price: this.price(),
}
this.productAdded.emit(productAdded);
this.resetFields();
}
resetFields() {
this.name.set('');
this.price.set(0);
}
}
2. product-list.component.ts
– Consumes products with input()
import { Component, input } from '@angular/core';
import { Product } from '../product-add/product-add.component';
@Component({
selector: 'product-list',
standalone: true,
template: `
Product List
Si cargo
@for (product of products(); track product.id; let idx = $index) {
{{ product.name }} - ${{ product.price }}
}
`
})
export class ProductListComponent {
products = input.required<Product[]>();
}
3. product-page.component.ts
– Orchestrates everything with signal()
import { Component, signal } from '@angular/core';
import { ProductAddComponent, Product } from '../product-add/product-add.component';
import { ProductListComponent } from '../product-list/product-list.component';
@Component({
selector: 'product-page',
standalone: true,
imports: [ProductAddComponent, ProductListComponent],
template: `
Product Dashboard
`
})
export class ProductPageComponent {
products = signal<Product[]>([]);
addProduct(newProduct: Product) {
this.products.update(p => [...p, newProduct]);
}
}
What This Shows
Feature | Demonstrated |
---|---|
input.required |
In ProductListComponent
|
output |
In ProductAddComponent
|
signal |
In ProductPageComponent
|
Reactive flow | Between child and parent |
Standalone components | ✅ |