LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 2018 min read

Introduction to Signals

Learn Signals, Angular's modern, explicit reactivity primitive for holding and reading state.

What Is a Signal?

A signal is a wrapper around a value that notifies anything reading it whenever that value changes. Unlike a plain class property, reading a signal is an explicit function call — signal() — which is what lets Angular track precisely which parts of the UI depend on it.

Reading and Writing a Signal

import { Component, signal } from '@angular/core';
@Component({
selector: 'app-counter',
standalone: true,
template: `
<button (click)="increment()">Clicked {{ count() }} times</button>
`,
})
export class CounterComponent {
count = signal(0);
increment() {
this.count.set(this.count() + 1);
}
}
Reading Always Uses ()

count() reads the current value — count is the signal object itself, not the value. This is the same explicit-call pattern used by other frameworks' fine-grained reactivity systems.

Signals in Templates

A signal is called with () directly in the template too, exactly like in the component class — Angular's template compiler understands this and tracks the dependency automatically.

<p>{{ count() }}</p>
<p [class.zero]="count() === 0">Status</p>

update() vs set()

set() replaces a signal's value entirely; update() derives the new value from the current one, which is often clearer and safer for anything based on the previous state.

count.set(10); // replace entirely
count.update(c => c + 1); // derive from current value

Why Signals Were Introduced

Classic Angular relies on Zone.js to detect when something might have changed, then re-checks the entire component tree to find what actually did — broad and somewhat wasteful. Signals let Angular know exactly which values changed and exactly which parts of the template depend on them, enabling much more precise, efficient updates.

Classic (Zone.js)Signals
Change detectionRuns broadly after any async eventRuns precisely, only for affected bindings
Reading stateDirect property accessExplicit function call: mySignal()
Dependency trackingImplicit, via Zone.js patchingExplicit, tracked per-signal

Common Beginner Mistakes

Forgetting the () when reading a signal

{{ count }} in a template renders the signal object's description, not its value — you need {{ count() }}.

Trying to assign directly to a signal, like count = 5

A signal's value is only changed through .set() or .update() — direct assignment replaces the signal itself, which is almost never what you want.

FAQs

No — classic property-based reactivity and signals interoperate, and you can adopt signals incrementally in new or refactored code.

Conceptually, yes — all three wrap a value so a framework can track reads and react to writes, though the exact syntax and semantics differ.

Summary

Signals give Angular explicit, fine-grained reactivity — read with (), written with .set()/.update(). Next, you'll learn computed() and effect(), the two companion primitives that build on signals.

Next Lesson →

computed() and effect()