Component Signals

Back

Loading concept...

🎯 Angular Signals: Component Signals

The Walkie-Talkie Story đź“»

Imagine you have a team of friends building a treehouse. Each friend has a walkie-talkie. When one friend finds a nail, they press a button and say “Found a nail!” — and everyone who needs to know hears it instantly.

That’s exactly what Angular Component Signals do.

Your components are like friends in the treehouse. They need to:

  • Receive messages (Signal Inputs)
  • Send messages back (Signal Outputs)
  • Share toys that anyone can change (Model Inputs)
  • Find things in the treehouse (Signal Queries)
  • Translate between old and new walkie-talkies (toSignal & toObservable)

Let’s meet each one!


📥 Signal Inputs: Receiving Messages

What Is It?

A Signal Input is like a mailbox on your component’s door. Parent components drop letters (data) into it. Your component reads them as signals.

Simple Example

Old Way (Before):

@Input() name = '';

New Way (Signal Input):

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

name = input<string>('');

Why It’s Better

Think of it like this:

  • Old mailbox: You had to keep checking if mail arrived
  • Signal mailbox: It rings a bell when mail arrives!
// Reading the value
const currentName = this.name();

// React when it changes
effect(() => {
  console.log('Name changed to:', this.name());
});

Required Inputs

Sometimes you MUST have a letter. No letter = no entry!

// This MUST be provided by parent
userId = input.required<number>();

Transform Inputs

What if the letter is in French but you speak English? Transform it!

age = input(0, {
  transform: (value: string) => parseInt(value, 10)
});

Parent sends "25" (string) → You receive 25 (number)


🔄 Model Inputs: Two-Way Walkie-Talkies

What Is It?

A Model Input is special. It’s like a walkie-talkie where both people can talk AND listen. When you change the value, the parent knows. When the parent changes it, you know!

Simple Example

Think of a toy that two kids share:

  • Kid A changes the color → Kid B sees the new color
  • Kid B changes the color → Kid A sees the new color
import { model } from '@angular/core';

// This creates a two-way connection!
checked = model<boolean>(false);

In the Template

<!-- Parent component -->
<my-toggle [(checked)]="isOn"></my-toggle>

The banana-in-a-box [()] means: “send AND receive!”

Changing the Value

// Read current value
const isChecked = this.checked();

// Change it (parent will know!)
this.checked.set(true);

// Or update based on current value
this.checked.update(current => !current);
graph TD A["Parent Component"] -->|sends value| B["Model Input"] B -->|notifies back| A B -->|updates| C["Child Component"] C -->|changes value| B

📤 Signal Outputs: Sending Messages Out

What Is It?

A Signal Output is like a megaphone. When something happens in your component, you shout it out so parents can hear.

Simple Example

Imagine a doorbell. When someone presses it, the house hears “DING!”

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

// Create a doorbell
buttonClicked = output<void>();

// Ring it!
onClick() {
  this.buttonClicked.emit();
}

With Data

What if the doorbell could say WHO is at the door?

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

// Doorbell that announces the visitor
visitorArrived = output<string>();

announceVisitor(name: string) {
  this.visitorArrived.emit(name);
}

Parent Listening

<my-doorbell (visitorArrived)="greet($event)">
</my-doorbell>
greet(visitorName: string) {
  console.log('Hello, ' + visitorName + '!');
}

🔍 Signal Queries: Finding Things

What Is It?

Signal Queries help you find things inside your component. Like a flashlight in a dark room!

There are 4 types:

Query What It Finds
viewChild One thing in your template
viewChildren Many things in your template
contentChild One thing a parent put inside you
contentChildren Many things a parent put inside you

viewChild: Find One Thing

import { viewChild, ElementRef } from '@angular/core';

// Find the input box
searchBox = viewChild<ElementRef>('searchInput');
<input #searchInput type="text">
focusSearch() {
  // searchBox is a signal, so call it!
  this.searchBox()?.nativeElement.focus();
}

viewChildren: Find Many Things

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

// Find ALL buttons
buttons = viewChildren<ElementRef>('btn');
<button #btn>One</button>
<button #btn>Two</button>
<button #btn>Three</button>
countButtons() {
  // Returns an array inside a signal
  return this.buttons().length; // 3
}

contentChild & contentChildren

These find things that a parent placed inside your component.

// Child component
import { contentChild, contentChildren } from '@angular/core';

// Find projected content
header = contentChild<ElementRef>('cardHeader');
items = contentChildren<ItemComponent>(ItemComponent);
<!-- Parent using the child -->
<my-card>
  <h2 #cardHeader>Hello!</h2>
  <app-item></app-item>
  <app-item></app-item>
</my-card>
graph TD A["viewChild"] -->|finds ONE| B["in your template"] C["viewChildren"] -->|finds MANY| B D["contentChild"] -->|finds ONE| E["projected by parent"] F["contentChildren"] -->|finds MANY| E

🌉 toSignal: Turning Streams into Signals

What Is It?

Imagine you have an old radio that plays music (Observable). But your new house only has signal-speakers (Signals).

toSignal is the adapter that connects them!

Simple Example

import { toSignal } from '@angular/core/rxjs-interop';
import { interval } from 'rxjs';

// Old radio: plays a number every second
const timer$ = interval(1000);

// Adapter: now it's a signal!
timerSignal = toSignal(timer$);

In Templates

<!-- No need for async pipe! -->
<p>Seconds: {{ timerSignal() }}</p>

With Initial Value

What if the radio hasn’t started playing yet?

// Start with 0 while waiting
timerSignal = toSignal(timer$, { initialValue: 0 });

With HTTP Calls

users = toSignal(
  this.http.get<User[]>('/api/users'),
  { initialValue: [] }
);

đź’ˇ Pro Tip: toSignal automatically subscribes AND unsubscribes. No memory leaks!


đź”™ toObservable: Signals Back to Streams

What Is It?

Now imagine the opposite. Your friend has a new signal-walkie-talkie, but their house only has old radios.

toObservable converts signals back to observables.

When Would You Need This?

  • Using RxJS operators like debounceTime, switchMap
  • Connecting to libraries that expect observables
  • Complex async operations

Simple Example

import { signal } from '@angular/core';
import { toObservable } from '@angular/core/rxjs-interop';
import { debounceTime } from 'rxjs/operators';

// A signal
searchTerm = signal('');

// Convert to observable
searchTerm$ = toObservable(this.searchTerm);

// Now use RxJS magic!
results$ = this.searchTerm$.pipe(
  debounceTime(300),
  switchMap(term => this.searchService.find(term))
);

Practical Use Case: Search with Debounce

@Component({...})
export class SearchComponent {
  query = signal('');

  results = toSignal(
    toObservable(this.query).pipe(
      debounceTime(300),
      distinctUntilChanged(),
      switchMap(q => this.api.search(q))
    ),
    { initialValue: [] }
  );
}
graph LR A["Signal"] -->|toObservable| B["Observable"] B -->|RxJS operators| C["Transformed Observable"] C -->|toSignal| D["Signal Again!"]

🎯 Quick Summary

Feature Purpose Example
input() Receive data from parent name = input<string>('')
input.required() Must receive data id = input.required<number>()
model() Two-way binding checked = model(false)
output() Send events to parent clicked = output<void>()
viewChild() Find one element viewChild('ref')
viewChildren() Find many elements viewChildren('ref')
contentChild() Find projected element contentChild('ref')
contentChildren() Find projected elements contentChildren(Comp)
toSignal() Observable → Signal toSignal(obs$)
toObservable() Signal → Observable toObservable(sig)

🎉 You Did It!

You now understand Angular’s Component Signals! They’re like a modern walkie-talkie system for your components:

  • Signal Inputs = Mailboxes that ring when mail arrives
  • Model Inputs = Two-way walkie-talkies
  • Signal Outputs = Megaphones to announce events
  • Signal Queries = Flashlights to find things
  • toSignal = Old radio → New speaker adapter
  • toObservable = New speaker → Old radio adapter

Go build something amazing! 🚀

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.