Angular Signals
A signal is a box that holds a value and tells Angular whenever that value changes. Angular then updates only the parts of the page that use the box. Signals make data flow simple to read and fast to run. They are a core feature of modern Angular, and new projects use them for most component data.
The Scoreboard Idea
Picture a cricket scoreboard at a stadium. The scorer changes one number, and every screen in the stadium shows the new number at once. Nobody walks around to update each screen. A signal works like that scorer. You change the value in one place, and every template that reads it refreshes automatically.
+-------------+
| SIGNAL |
| score = 42 |
+------+------+
| change notifies
+---------+---------+
v v
+-----------+ +-----------+
| Header | | Summary |
| shows 42 | | shows 42 |
+-----------+ +-----------+
Create and Read a Signal
Call the signal function with a starting value. Read the value by calling the signal like a function.
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-counter',
template: `
<p>Count: {{ count() }}</p>
<button (click)="increase()">Add</button>
`
})
export class CounterComponent {
count = signal(0);
increase() {
this.count.update(value => value + 1);
}
}
The parentheses after count matter. They tell Angular to read the current value and to watch it for changes.
Change a Signal
Two methods change a signal. The set method replaces the value. The update method calculates a new value from the old one.
this.count.set(10);
this.count.update(old => old * 2);
Computed Signals
A computed signal calculates its value from other signals. It recalculates only when one of those signals changes. A bill total works as a good example. The total depends on the price and the quantity. When either one changes, the total changes without extra code.
import { signal, computed } from '@angular/core';
price = signal(50);
quantity = signal(2);
total = computed(() => this.price() * this.quantity());
You cannot set a computed signal directly. It stays read-only, so the formula remains the single source of truth.
Effects
An effect runs code every time the signals inside it change. Use effects for side actions, such as saving a value to local storage or writing a log message.
import { effect } from '@angular/core';
constructor() {
effect(() => {
console.log('Count is now', this.count());
});
}
Avoid changing other signals inside an effect. That pattern creates confusing chains. Prefer computed signals for values that depend on other values.
Signals with Arrays and Objects
A signal detects a change when you give it a new value. Changing an item inside the old array does not notify Angular. Create a fresh array instead.
tasks = signal<string[]>([]);
addTask(name: string) {
this.tasks.update(list => [...list, name]);
}
The three dots copy the old items into a new array, and the new item joins at the end.
Signals Compared with Plain Variables
| Feature | Plain Variable | Signal |
|---|---|---|
| Tells Angular about changes | No | Yes |
| Supports computed values | No | Yes |
| Updates only affected parts | No | Yes |
| Reads with parentheses | No | Yes |
Real-Life Example
Think of a shopping cart page. A signal holds the list of items. A computed signal calculates the total price from that list. A second computed signal counts the items for the cart badge in the header. When the visitor adds an item, one update call refreshes the list, the total, and the badge together.
Key Points
- A signal stores a value and notifies Angular on changes.
- Read with
count(), and change withsetorupdate. - Computed signals derive new values from other signals.
- Effects run side actions when signals change.
