Angular signals(๐๐)
for years, Angular relied on Zone.js to handle change detection. While it worked behind the scenes to keep the UI in sync with the data, it often felt like a blunt instrument โ checking the entire component tree for changes whenever any asynchronous event occurred.
Get Mohamed Aymanโs stories inย yourย inbox
Join Medium for free to get updates fromย thisย writer.
Angular Signals represent a paradigm shift in how the framework manages state and triggers UI updates. Introduced as a developer preview in Angular 16 and fully stabilized in subsequent releases, Signals bring fine-grained reactivity to the ecosystem. Instead of guessing what changed, Angular now knows exactly which piece of data mutated and precisely which part of the DOM needs an update.
What is a Signal?
At its core, a Signal is a wrapper around a value that notifies interested consumers whenever that value changes. Think of it as a value with a built-in megaphone.Signals are synchronous, deterministic, and always possess an initial value. Because they track where they are read, they establish a dependency graph automatically.
The Three Pillars of Signals
Angularโs reactivity model relies on three fundamental building blocks:
- Writable Signals: Signals that can be directly updated.
- Computed Signals: Read-only signals that derive their value from other signals.
- Effects: Operations that run automatically whenever the signals they read change.
Deep Dive into the Core Pillars
Writable Signals
Writable signals allow you to read and write values directly. You initialize them using the signal() function and update them using .set() or .update().
- Reading a signal: You invoke it like a function:
mySignal(). .set(): Replaces the value entirely..update(): Computes a new value based on the current value.
In first image, we see the component's state variables being initialized. It mixes traditional primitive properties with Angular's newer reactive paradigm:
- Line 1โ4: Standard TypeScript properties (
value,rating,review) are declared, allowing for direct mutations. - Line 5: A Writable Signal named
productsis initialized usingsignal<IProduct null |>(null). - By using a Signal, Angular sets up an explicit, fine-grained dependency graph for the product data. Whenever this specific data changes, any template or computed function bound to it will be notified automatically without requiring a full component tree re-render.
2. Fetching and Updating Data (code2.png)
The second image file demonstrates how the component handles asynchronous router streams and updates the declared states inside the ngOnInit lifecycle hook:
- Route Subscription (Lines 2โ5): The code subscribes to Angularโs
route.paramMapto grab the current productidfrom the URL. - API Execution & State Mutation (Lines 7โ12): Once it receives an ID, it calls an API service (
this.api.show<IProduct>) to fetch the product details. - The Crucial Distinction: Notice the two different styles of updating state inside the
nextblock: - On Line 9, the Signal is updated using its reactive setter method:
this.products.set(data). - On Lines 10โ11, the traditional properties are updated via standard assignment:
this.value = data.averageStars.
3. Declarative UI Binding (code4.jpg)
The third image file displays the HTML template (written with Tailwind CSS utility classes and PrimeNG components like <p-rating> and <p-button>), where the magic of Signals shines in the DOM.
- Reading the Signal: Because
productsis a Signal, it must be read by invoking it like a function:products(). We see this clean syntax scattered throughout the template (e.g.,products()?.photoson line 3,products()?.nameon line 7, andproducts()?.descriptionon line 24). - Modern Control Flow: Lines 11โ16 utilize Angularโs modern built-in
@if/@elsesyntax to evaluate whether a product rating value exists, displaying the numerical value or fallback text cleanly. - Interactivity: On line 29, the template handles user interaction by binding a click event to an action, passing the unwrapped, non-null value of the signal downstream:
setBasketValue(products()!).
The Big Picture
Together, these files show a classic modern Angular workflow. By shifting from standard properties to the products signal in First image, updating it explicitly via .set() in Second image, and invoking it synchronously as products() in Third Image, the application unlocks localized, high-performance UI updates completely independent of heavy, global change detection cycles.




