Angular 4: Managing State with Signals
/ 2 min read
Table of Contents
Our service works, but every consumer can currently change its signal. We will protect writes, calculate useful totals, and save topics between refreshes.
Three signal tools
signal()stores writable state.computed()derives a value from other signals.effect()performs an external side effect when a signal changes.
1. Protect the state
private readonly topicsState = signal<TopicItem[]>(initialTopics);readonly topics = this.topicsState.asReadonly();Components can read topics, but only service methods can update topicsState. This creates one clear place for business rules.
2. Calculate totals
readonly completedCount = computed( () => this.topicsState().filter(topic => topic.completed).length);
readonly pendingCount = computed( () => this.topicsState().filter(topic => !topic.completed).length);Why not use an effect to calculate these totals?
The totals are derived state. computed() expresses that relationship directly and always stays synchronized. Effects are for work outside the signal graph.
3. Save to local storage safely
This project uses SSR, where localStorage does not exist. Wait until Angular is running in the browser:
private readonly storageReady = signal(false);
constructor() { afterNextRender(() => { const savedTopics = localStorage.getItem('topics');
if (savedTopics) { try { this.topicsState.set(JSON.parse(savedTopics) as TopicItem[]); } catch { localStorage.removeItem('topics'); } }
this.storageReady.set(true); });
effect(() => { const topics = this.topicsState();
if (this.storageReady()) { localStorage.setItem('topics', JSON.stringify(topics)); } });}The readiness flag prevents the save effect from overwriting existing storage before it has been loaded.
Checkpoint
Toggle a topic, refresh the page, and confirm the value remains. Then inspect Local Storage in browser developer tools.
Small challenge
Handle valid JSON with the wrong shape. For example, decide what should happen if storage contains {} instead of an array.
Navigation: Previous: Services · Series overview · Next: Reactive forms