Creating Signals
Signals are reactive containers for values. When a signal changes, all dependent computations and templates automatically update.
Creating a Signal
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-counter',
template: `
<p>Count: {{ count() }}</p>
<button (click)="increment()">+</button>
<button (click)="decrement()">-</button>
`,
})
export class CounterComponent {
count = signal(0);
increment(): void {
this.count.update(c => c + 1);
}
decrement(): void {
this.count.update(c => c - 1);
}
}
set() vs update()
// set() — replace the value directly
this.count.set(10);
// update() — compute new value from current
this.count.update(c => c + 1);
Reading Signals
// In component class — call as function
const currentValue = this.count();
// In template — call as function
<p>{{ count() }}</p>
Signal Types
// Primitive
const name = signal<string>('Alice');
// Object
const user = signal<User>({ id: 1, name: 'Alice' });
// Array
const items = signal<string[]>([]);
// Readonly (prevent external writes)
const readonlyCount = this.count.asReadonly();
Computed Signals
Computed signals derive values from other signals. They are lazy and memoized.
Creating Computed Signals
import { Component, signal, computed } from '@angular/core';
@Component({
selector: 'app-cart',
template: `
<p>Items: {{ itemCount() }}</p>
<p>Total: {{ total() | currency: 'USD' }}</p>
<p>Tax: {{ tax() | currency: 'USD' }}</p>
<p>Grand Total: {{ grandTotal() | currency: 'USD' }}</p>
`,
})
export class CartComponent {
items = signal<CartItem[]>([
{ name: 'Widget', price: 10 },
{ name: 'Gadget', price: 20 },
]);
itemCount = computed(() => this.items().length);
total = computed(() =>
this.items().reduce((sum, item) => sum + item.price, 0)
);
tax = computed(() => this.total() * 0.1);
grandTotal = computed(() => this.total() + this.tax());
}
Computed Signal Characteristics
- Lazy — Only computed when read
- Memoized — Cached until dependencies change
- Read-only — Cannot be set or updated
// BAD: Computed signals are read-only
this.total.set(100); // Error!
// GOOD: Update the source signal
this.items.update(items => [...items, newItem]);
Computed with Conditions
const isEligible = computed(() =>
this.age() >= 18 && this.hasConsent()
);
const message = computed(() => {
if (this.isEligible()) {
return 'Access granted';
}
return 'Access denied';
});
Quiz
1. How do you create a signal?
2. What is a computed signal?
3. How do you update a signal based on its current value?
Flashcards
Question
How do you create a signal?
Click to reveal answer
Answer
signal(value) — read with signal(), update with set() or update().
Question
What is a computed signal?
Click to reveal answer
Answer
Derived signal that is lazy and memoized. Read-only.
Question
set() vs update()?
Click to reveal answer
Answer
set() replaces the value. update() computes new value from current.
Revision Notes
Key Takeaways
- 1. signal() creates reactive values
- 2. Read signals by calling them: signal()
- 3. set() replaces, update() derives from current
- 4. computed() creates lazy, memoized derived values
Interview Tips
- • Explain the difference between set() and update()
- • Be ready to describe computed signal characteristics
- • Mention that signals enable fine-grained reactivity
Cheat Sheet
Signals Cheat Sheet
Create:
count = signal(0);
Read:
count() // in class or template
Update:
count.set(10);
count.update(c => c + 1);
Computed:
total = computed(() => this.items().reduce((s, i) => s + i.price, 0));
Readonly:
readonlySignal = signal.asReadonly();