Angular Signals
Learn Angular Signals, including signal(), set(), update(), computed(), effect(), dependency tracking, OnPush, control flow, HttpClient, RxJS interoperability (toSignal/toObservable), Signal Stores, enterprise architecture, performance, common mistakes, and interview questions.
Learning Objectives
By the end of this lesson, you will understand:
- What Angular Signals are and why they were introduced.
- How Signals improve state management.
- The difference between Signals and traditional Angular change detection.
- How to create writable Signals using
signal(). - How to read Signal values.
- How to update Signals using
set()andupdate(). - How
computed()creates derived state. - How
effect()reacts to Signal changes. - Writable vs read-only Signals.
- Signal dependency tracking.
- Dynamic dependency tracking.
- Signal equality.
- Signals with Components.
- Signals with
OnPushChange Detection. - Signals with
@if,@for, and@switch. - Signals with HttpClient.
- Signals with RxJS (
toSignal()andtoObservable()). - Building scalable Signal Stores.
- Enterprise state management architecture.
- Performance optimization.
- Real-world examples.
- Common mistakes.
- Advanced interview questions.
Introduction
Every Angular application has state.
For example:
Current UserThemeCoursesShopping CartNotificationsLoading StatusError MessagesAuthentication
Whenever state changes, the UI should automatically update.
Imagine TechLearningPro.
User Opens Angular Course↓Course Loads↓Lessons Display↓User Completes Lesson↓Progress Updates↓Certificate Unlocks
Every one of these steps is a state change.
Managing state efficiently is one of the biggest challenges in frontend development.
What Are Angular Signals?
Angular Signals are reactive state containers.
A Signal stores a value and automatically notifies Angular whenever that value changes.
Think of a Signal as a smart variable.
Unlike a normal variable:
let count = 0;
A Signal is reactive.
const count = signal(0);
Architecture:
Signal│▼State Changes│▼Angular Detects Change│▼Update UI
Why Angular Introduced Signals
Traditional Angular relied heavily on:
- Zone.js
- Global Change Detection
- RxJS for local state
This worked well but sometimes caused unnecessary checks.
Signals introduce fine-grained reactivity.
Instead of checking the whole application, Angular updates only the parts that depend on the changed Signal.
Architecture:
BeforeApplication│▼Change Detection│▼Many Components Checked-----------------------------------With SignalsSignal Changed│▼Only Dependent Components Update
Creating Your First Signal
Use the signal() function.
import { signal } from '@angular/core';count = signal(0);
The Signal now stores the value 0.
Reading a Signal
Signals are read by calling them like a function.
count();
Example:
console.log(count());
Output:
0
Architecture:
Signal↓count()↓Value
Updating a Signal using set()
Use set() when replacing the value completely.
count.set(10);
Now:
count();
returns:
10
Updating a Signal using update()
Suppose the current value is:
10
Increment:
count.update(value => value + 1);
Result:
11
Architecture:
Current Value↓update()↓New Value
set() vs update()
Use:
count.set(100);
when replacing the value.
Use:
count.update(v => v + 1);
when calculating a new value from the current value.
Real-Time Counter Example
count = signal(0);increment() {this.count.update(v => v + 1);}
Template:
<p>{{ count() }}</p><button (click)="increment()">Increment</button>
Architecture:
Button Click↓update()↓Signal Changes↓UI Updates
Signals with Objects
Signals can store objects.
user = signal({id: 1,name: 'Jagannath',role: 'ADMIN'});
Read:
user().name
Update:
user.update(u => ({...u,role: 'STUDENT'}));
Signals with Arrays
Example:
courses = signal(['Angular','Java','Spring Boot']);
Add a course:
courses.update(list => [...list,'Kubernetes']);
Architecture:
Courses Signal↓Update Array↓Angular UI Updates
computed()
Many values are derived from other values.
Suppose:
price = signal(1000);quantity = signal(3);
Total price should always be:
3000
Instead of manually calculating it everywhere:
Use:
total = computed(() =>this.price() * this.quantity());
Architecture:
Price Signal↓Computed↑Quantity Signal↓Total
Whenever either Signal changes, the computed Signal updates automatically.
Real-Time Example: TechLearningPro Progress
Signals:
completedLessons = signal(18);totalLessons = signal(25);
Computed:
progress = computed(() =>(this.completedLessons() / this.totalLessons()) * 100);
Output:
72%
No manual calculation is required.
effect()
Sometimes we don't want to calculate a value.
We want to perform an action.
For example:
Save ProgressAnalyticsLoggingNotifications
Use:
effect(() => {console.log(this.count());});
Whenever count changes:
Console Updates Automatically
Architecture:
Signal Changes↓effect()↓Side Effect
Writable vs Read-only Signals
Writable:
count = signal(0);
Read-only:
progress = computed(...);
Architecture:
signal()↓Writable↓computed()↓Read Only
Dependency Tracking
Angular automatically tracks dependencies.
Example:
total = computed(() =>this.price() * this.quantity());
Angular knows:
TotalDepends OnPriceQuantity
If either changes:
Only total recomputes.
Dynamic Dependency Tracking
Signals only track values actually read during execution.
Example:
showPrice = signal(true);price = signal(100);discount = signal(20);display = computed(() => {if (this.showPrice()) {return this.price();}return this.discount();});
When showPrice() is true:
Only price() is tracked.
Signals with Components
Example:
@Component({...})export class DashboardComponent {user = signal('Jagannath');}
Template:
<h2>{{ user() }}</h2>
Whenever:
user.set('Krishna');
Angular automatically updates the UI.
Signals with OnPush Change Detection
Traditionally, OnPush components required careful management of immutable data and change detection.
Signals work naturally with OnPush.
Architecture:
Signal Changes↓OnPush Component↓Only Required View Updates
This helps create highly performant applications.
Signals with Control Flow
Signals integrate perfectly with modern control flow.
Example:
@if (isLoggedIn()) {<app-dashboard />} @else {<app-login />}
Collection:
@for (course of courses();track course.id) {<app-course-card />}
Signals with HttpClient
Example:
courses = signal<Course[]>([]);loading = signal(true);this.http.get<Course[]>(...).subscribe(data => {this.courses.set(data);this.loading.set(false);});
Template:
@if (loading()) {<app-spinner />} @else {@for (course of courses();track course.id) {<app-course-card />}}
Signals and RxJS
Angular provides interoperability.
Observable → Signal
toSignal()
Signal → Observable
toObservable()
Architecture:
Observable↓toSignal()↓Signal↓toObservable()↓Observable
This allows gradual migration from RxJS.
Building a Signal Store
Instead of placing Signals inside many components:
Create a feature store.
Example:
@Injectable()export class CourseStore {courses = signal<Course[]>([]);loading = signal(false);error = signal('');}
Architecture:
Component↓Course Store↓Signals↓API
TechLearningPro Signal Architecture
Course Store│├── courses()├── loading()├── progress()├── selectedLesson()├── completedLessons()└── searchText()↓Computed Signals↓Filtered Lessons↓Angular UI
This architecture scales very well.
Performance Benefits
Signals provide:
Fine-Grained UpdatesLess Change DetectionCleaner StateBetter PerformanceSimpler Components
Common Mistakes
Mutating Objects
Avoid:
user().name = 'Krishna';
Instead:
user.update(u => ({...u,name: 'Krishna'}));
Using effect() Everywhere
Effects are for side effects.
Don't use them for derived values.
Use:
computed()
instead.
Business Logic Inside Components
Move Signals into feature stores.
Too Many Global Signals
Keep Signals close to the feature that owns them.
Enterprise Architecture
Backend API↓Course Service↓Course Store↓Signals↓Computed Signals↓Angular Components↓UI
This is the recommended architecture for scalable Angular applications.
Advanced interview questions
Interview Prep
Practice concise answers, then expand each card for the explanation.
1BeginnerQuestionWhat is an Angular Signal?+
Answer
2BeginnerQuestionHow do you create a Signal?+
Answer
count = signal(0);3BeginnerQuestionHow do you read a Signal?+
Answer
count();4BeginnerQuestionDifference between `set()` and `update()`?+
Answer
set()replaces the value completely.update()calculates a new value based on the current value.
5IntermediateQuestionWhat is `computed()`?+
Answer
6IntermediateQuestionWhat is `effect()`?+
Answer
effect() executes side effects whenever the Signals it reads change. It is commonly used for logging, analytics, local storage synchronization, or other side-effect operations.7AdvancedQuestionCan Signals replace RxJS?+
Answer
8IntermediateQuestionWhy are Signals faster?+
Answer
9IntermediateQuestionCan Signals work with OnPush?+
Answer
OnPush components and help simplify efficient UI updates.10AdvancedQuestionWhat is the recommended enterprise architecture?+
Answer
Summary
Angular Signals simplify reactive state management while improving performance and readability.
Backend API│▼Service Layer│▼Signal Store│├── Writable Signals├── Computed Signals└── Effects│▼Angular Components│▼@if / @for / @switch│▼User Interface
The most important principle is:
The most important principle is: Use Signals to represent state, computed() to derive state, and effect() only for side effects. Keep business logic in services or stores and let components focus on rendering.
Next Lesson
Angular Change Detection — In the next lesson, you'll learn:
- How Angular Change Detection works internally.
- Default vs
OnPushChange Detection. - Zone.js and its role.
- Zoneless Angular.
- Change detection tree and traversal.
ChangeDetectorRef.markForCheck()vsdetectChanges().detach()andreattach().- Signals and Change Detection.
- Performance optimization techniques.
- Debugging change detection issues.
- Enterprise best practices.
- Advanced interview questions.