<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Placide</title>
    <description>The latest articles on DEV Community by Placide (@rigole).</description>
    <link>https://dev.to/rigole</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3577091%2F5864aeaf-1a33-4e9f-b635-0cd1638b5076.jpeg</url>
      <title>DEV Community: Placide</title>
      <link>https://dev.to/rigole</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rigole"/>
    <language>en</language>
    <item>
      <title>Building Real-Time Dashboards in Angular with WebSockets — A Complete Guide</title>
      <dc:creator>Placide</dc:creator>
      <pubDate>Sun, 21 Jun 2026 12:24:28 +0000</pubDate>
      <link>https://dev.to/rigole/building-real-time-dashboards-in-angular-with-websockets-a-complete-guide-10he</link>
      <guid>https://dev.to/rigole/building-real-time-dashboards-in-angular-with-websockets-a-complete-guide-10he</guid>
      <description>&lt;p&gt;Most dashboards are built the same way: the user lands on the page, data loads, and then... it sits there. Stale. Until the user hits refresh or you set up an awkward polling interval that hammers your server every few seconds.&lt;br&gt;
There's a better way. WebSockets give you a persistent, two-way connection between your Angular app and your server — meaning your dashboard updates the moment new data exists, with zero wasted requests.&lt;br&gt;
In this article we'll build a complete real-time dashboard in Angular from scratch — WebSocket service, Signal-based components, auto-reconnection, and production-ready patterns.&lt;/p&gt;
&lt;h2&gt;
  
  
  How WebSockets Differ From Regular HTTP
&lt;/h2&gt;

&lt;p&gt;Before writing any code, it's worth understanding what makes WebSockets special.&lt;/p&gt;

&lt;p&gt;Regular HTTP:&lt;br&gt;
Client → "Give me data" → Server&lt;br&gt;
Client ← "Here's your data" ← Server&lt;br&gt;
[Connection closes]&lt;/p&gt;

&lt;p&gt;WebSocket:&lt;br&gt;
Client ←→ Server [Connection stays open]&lt;br&gt;
Server → "New data!" → Client  (anytime)&lt;br&gt;
Server → "More data!" → Client (anytime)&lt;br&gt;
Client → "Send this" → Server  (anytime&lt;/p&gt;

&lt;p&gt;For a real-time dashboard showing live metrics, user activity, or financial data — the WebSocket model is a natural fit. The server pushes updates the moment they happen. No polling, no refresh button, no stale data.&lt;/p&gt;
&lt;h2&gt;
  
  
  Project Setup
&lt;/h2&gt;

&lt;p&gt;For this article we'll build a dashboard that shows three live metrics: active users, requests per second, and server CPU usage.&lt;br&gt;
Start with a fresh Angular 22 project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng new realtime-dashboard &lt;span class="nt"&gt;--standalone&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;realtime-dashboard
ng serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;RxJS ships with Angular so no extra dependencies are needed — webSocket from rxjs/webSocket handles everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 — Define Your Data Model
&lt;/h2&gt;

&lt;p&gt;Start with a clear TypeScript interface for the data your server will push:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// core/models/dashboard.model.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;DashboardMetrics&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;activeUsers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;requestsPerSecond&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;cpuUsage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;MetricAlert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;warning&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;critical&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DashboardEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;metrics&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DashboardMetrics&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;alert&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MetricAlert&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2 — The WebSocket Service
&lt;/h2&gt;

&lt;p&gt;This is the heart of your real-time dashboard. One service manages the connection, handles errors, and exposes clean Observables for your components to consume:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// core/services/dashboard-socket.service.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;inject&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;webSocket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WebSocketSubject&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rxjs/webSocket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;EMPTY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;shareReplay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;takeUntil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DashboardEvent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DashboardMetrics&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MetricAlert&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../models/dashboard.model&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../environments/environment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DashboardSocketService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;socket$&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WebSocketSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DashboardEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;destroy$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Subject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;connected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;connection$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DashboardEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;socket$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;webSocket&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DashboardEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wsUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;socket$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[WebSocket] Connection error:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;EMPTY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nf"&gt;takeUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroy$&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;shareReplay&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;bufferSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;refCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Stream of live metrics&lt;/span&gt;
  &lt;span class="nx"&gt;metrics$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DashboardMetrics&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connection$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;metrics&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;metrics&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DashboardMetrics&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Stream of alerts only&lt;/span&gt;
  &lt;span class="nx"&gt;alerts$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MetricAlert&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connection$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;alert&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;alert&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MetricAlert&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Send a message to the server&lt;/span&gt;
  &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DashboardEvent&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;socket$&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;socket$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;disconnect&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroy$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroy$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;socket$&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;socket$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  A few things worth noting here:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;shareReplay({ bufferSize: 1, refCount: true })&lt;/strong&gt; means multiple components can subscribe to the same connection without opening multiple WebSocket connections — crucial for a multi-widget dashboard.&lt;br&gt;
Separating &lt;strong&gt;metrics$&lt;/strong&gt; and &lt;strong&gt;alerts$&lt;/strong&gt; into distinct streams lets each component subscribe only to what it needs.&lt;br&gt;
The timer(0, 3000) pattern handles auto-reconnection: if the connection drops, it retries every 3 seconds.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 3 — A Metrics Store with Signals
&lt;/h3&gt;

&lt;p&gt;Rather than subscribing directly in each component, create a Signal-based store that holds the latest dashboard state. This gives you one source of truth across your entire dashboard:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// core/stores/dashboard.store.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DashboardSocketService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../services/dashboard-socket.service&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DashboardMetrics&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MetricAlert&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../models/dashboard.model&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DashboardStore&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;socketService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DashboardSocketService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Raw signals&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;_metrics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DashboardMetrics&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;_alerts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MetricAlert&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;_connected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Public readonly signals&lt;/span&gt;
  &lt;span class="nx"&gt;metrics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asReadonly&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;alerts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_alerts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asReadonly&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;connected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_connected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asReadonly&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Computed signals&lt;/span&gt;
  &lt;span class="nx"&gt;isCpuCritical&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_metrics&lt;/span&gt;&lt;span class="p"&gt;()?.&lt;/span&gt;&lt;span class="nx"&gt;cpuUsage&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;hasAlerts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_alerts&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;latestAlert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_alerts&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;metricsSub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;socketService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metrics$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_connected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_connected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;alertsSub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;socketService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alerts$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;alert&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_alerts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;clearAlerts&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_alerts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metricsSub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alertsSub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;socketService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disconnect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The store keeps the last 10 alerts with .slice(0, 10) — enough history to be useful without growing unbounded.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4 — The Dashboard Component
&lt;/h3&gt;

&lt;p&gt;With the store in place, the component becomes almost trivially simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// features/dashboard/dashboard.component.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;inject&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DashboardStore&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../core/stores/dashboard.store&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MetricCardComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/metric-card.component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AlertBannerComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/alert-banner.component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ConnectionStatusComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/connection-status.component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;MetricCardComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;AlertBannerComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ConnectionStatusComponent&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;app-connection-status [connected]="store.connected()" /&amp;gt;

    @if (store.hasAlerts()) {
      &amp;lt;app-alert-banner [alert]="store.latestAlert()!" (dismiss)="store.clearAlerts()" /&amp;gt;
    }

    @if (store.metrics(); as m) {
      &amp;lt;div class="metrics-grid"&amp;gt;
        &amp;lt;app-metric-card
          label="Active users"
          [value]="m.activeUsers"
          unit="users"
          color="blue"
        /&amp;gt;
        &amp;lt;app-metric-card
          label="Requests / sec"
          [value]="m.requestsPerSecond"
          unit="req/s"
          color="teal"
        /&amp;gt;
        &amp;lt;app-metric-card
          label="CPU usage"
          [value]="m.cpuUsage"
          unit="%"
          [color]="store.isCpuCritical() ? 'red' : 'green'"
        /&amp;gt;
      &amp;lt;/div&amp;gt;
    } @else {
      &amp;lt;div class="loading"&amp;gt;Connecting to server...&amp;lt;/div&amp;gt;
    }
  `&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DashboardComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DashboardStore&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The component has zero business logic. It just reads from the store and renders. That's exactly how it should be.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5 — The Metric Card Component
&lt;/h3&gt;

&lt;p&gt;A clean, reusable card that displays a single metric:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// features/dashboard/components/metric-card.component.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-metric-card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;div class="card" [class]="'card--' + color()"&amp;gt;
      &amp;lt;span class="card__label"&amp;gt;{{ label() }}&amp;lt;/span&amp;gt;
      &amp;lt;span class="card__value"&amp;gt;{{ value() | number:'1.0-0' }}&amp;lt;/span&amp;gt;
      &amp;lt;span class="card__unit"&amp;gt;{{ unit() }}&amp;lt;/span&amp;gt;
    &amp;lt;/div&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`
    .card {
      padding: 24px;
      border-radius: 12px;
      background: var(--card-bg, #f8f9fa);
      border-left: 4px solid var(--card-accent, #6c757d);
      transition: border-color 0.3s ease;
    }
    .card__label { font-size: 12px; color: #6c757d; text-transform: uppercase; }
    .card__value { font-size: 36px; font-weight: 500; display: block; }
    .card__unit  { font-size: 14px; color: #6c757d; }
    .card--blue  { --card-accent: #0d6efd; }
    .card--teal  { --card-accent: #0dcaf0; }
    .card--green { --card-accent: #198754; }
    .card--red   { --card-accent: #dc3545; }
  `&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MetricCardComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;unit&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 6 — Handling the Connection Status
&lt;/h3&gt;

&lt;p&gt;A small but important UX detail — always show the user whether they're connected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// features/dashboard/components/connection-status.component.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-connection-status&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;div class="status" [class.status--connected]="connected()"&amp;gt;
      &amp;lt;span class="dot"&amp;gt;&amp;lt;/span&amp;gt;
      {{ connected() ? 'Live' : 'Reconnecting...' }}
    &amp;lt;/div&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`
    .status { display: flex; align-items: center; gap: 6px; font-size: 13px; color: #dc3545; }
    .status--connected { color: #198754; }
    .dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; }
    .status--connected .dot { animation: pulse 2s infinite; }
    @keyframes pulse { 0%,100%{opacity:1} 50%{opacity:.4} }
  `&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConnectionStatusComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;connected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Simulating a WebSocket Server for Testing
&lt;/h4&gt;

&lt;p&gt;Don't have a real WebSocket server? Here's a minimal Node.js mock to test against:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// server/mock-ws.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WebSocketServer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ws&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocketServer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;wss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Client connected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metrics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;metrics&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;activeUsers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;requestsPerSecond&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;cpuUsage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;// Occasionally send an alert&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;alert&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;warning&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cpuUsage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;95&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CPU usage is critically high&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Mock WebSocket server running on ws://localhost:8080&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it with &lt;code&gt;node server/mock-ws.js&lt;/code&gt; and point your &lt;code&gt;environment.wsUrl&lt;/code&gt; to &lt;code&gt;ws://localhost:8080&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Production Checklist
&lt;/h3&gt;

&lt;p&gt;Before shipping your real-time dashboard to production:&lt;br&gt;
Authentication&lt;/p&gt;

&lt;p&gt;Pass your auth token as a query parameter or handle it on the first message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;webSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`wss://api.example.com/dashboard?token=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;authToken&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Exponential backoff
&lt;/h3&gt;

&lt;p&gt;Replace the fixed 3-second retry with exponential backoff to avoid hammering your server during outages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;retryWhen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;scan&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;retryWhen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;retryCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;retryCount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Environment configuration&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// environments/environment.prod.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;production&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;wsUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wss://api.yourapp.com/dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a dashboard where you only receive data (no need to send back), Server-Sent Events (SSE) is actually a simpler alternative worth considering. But if you need bidirectional communication — sending filters, subscribing to specific metrics, sending user actions — WebSockets are the right choice&lt;/p&gt;

&lt;p&gt;Building a real-time Angular dashboard with WebSockets is more accessible than it looks. The combination of RxJS's webSocket(), Angular Signals for state, and a clean store architecture gives you a production-ready foundation that scales as your dashboard grows.&lt;br&gt;
The key patterns to take away:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;One &lt;code&gt;WebSocketSubject&lt;/code&gt; shared across all components via &lt;code&gt;shareReplay&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A Signal-based store as the single source of truth&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Auto-reconnection built into the service layer&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Components that are pure — just reading from the store and rendering&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your users deserve data that's always fresh. Give them that — and retire the refresh button for good.&lt;/p&gt;

&lt;p&gt;Have you built real-time features in Angular? What approach did you use — WebSockets, SSE, or polling? Share your experience below! &lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>angular</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Angular 22 Is Here — Everything You Need to Know</title>
      <dc:creator>Placide</dc:creator>
      <pubDate>Sun, 07 Jun 2026 08:11:08 +0000</pubDate>
      <link>https://dev.to/rigole/angular-22-is-here-everything-you-need-to-know-4g3c</link>
      <guid>https://dev.to/rigole/angular-22-is-here-everything-you-need-to-know-4g3c</guid>
      <description>&lt;p&gt;Angular released v22 on June 3, 2026. And this one feels different.&lt;br&gt;
This isn't another incremental update. Angular 22 is a consolidation release — the experiments are over. &lt;strong&gt;Signal Forms, Zoneless architecture, and OnPush change detection&lt;/strong&gt; are all production-stable now. Years of work have converged into a single version that genuinely changes how you build Angular apps.&lt;br&gt;
Let's break down every major feature you need to know.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;code&gt;OnPush&lt;/code&gt; Is Now the Default Change Detection Strategy
&lt;/h2&gt;

&lt;p&gt;A decision that has been discussed in the Angular community since the very beginning is now reality: OnPush is the new default change detection strategy. Medium&lt;br&gt;
This makes perfect sense in a Signals-first world. Anyone using Signals gets precise notifications about changes, and OnPush takes full advantage of that — focusing change detection only on the components actually affected.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// If you need the old behavior,you''ll set it explicitly&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-legacy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;changeDetection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeDetectionStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Eager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// replaces the old 'Default'&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`...`&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LegacyCmp&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: the old &lt;code&gt;Default&lt;/code&gt; strategy is now deprecated and replaced by Eager. And don't worry about breaking changes — &lt;code&gt;ng update&lt;/code&gt; automatically sets &lt;code&gt;Eager&lt;/code&gt; on your existing components during migration if &lt;code&gt;OnPush&lt;/code&gt; was not explicitly set.&lt;/p&gt;

&lt;h2&gt;
  
  
  Signal Forms — Finally Stable
&lt;/h2&gt;

&lt;p&gt;Signal Forms are now stable and ready for production use. The path from experimental to stable was remarkably fast, made possible by extensive internal case studies at Google.&lt;/p&gt;

&lt;p&gt;The heart of Signal Forms is the form function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;linkedSignal&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;minLength&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/forms/signals&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;[...]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FlightEdit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;FlightDetailStore&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;flight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;linkedSignal&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;normalizeFlight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flight&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;flightForm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;form&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;required&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;required&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;minLength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is a &lt;code&gt;FieldTree&lt;/code&gt; — a deeply nested Signal structure where each property is represented as a Signal with full form status (&lt;code&gt;value&lt;/code&gt;, &lt;code&gt;dirty&lt;/code&gt;, &lt;code&gt;invalid&lt;/code&gt;, &lt;code&gt;errors&lt;/code&gt;). Bind it in your template with the &lt;code&gt;FormField&lt;/code&gt; directive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;[formField]=&lt;/span&gt;&lt;span class="s"&gt;"flightForm.from"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"flight-from"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;{{ flightForm.from().errors() | json }}&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No more verbose &lt;code&gt;FormGroup&lt;/code&gt; and &lt;code&gt;FormControl&lt;/code&gt; boilerplate. This is forms the Angular way in 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resource API — Stable and Production-Ready
&lt;/h2&gt;

&lt;p&gt;The Resource API and Signal Forms are now stable and ready for production use. The &lt;code&gt;resource&lt;/code&gt;, &lt;code&gt;rxResource&lt;/code&gt;, and &lt;code&gt;httpResource&lt;/code&gt; functions can all be safely used in production.&lt;/p&gt;

&lt;p&gt;The most convenient entry point is &lt;code&gt;httpResource&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;httpResource&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/common/http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;[...]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FlightSearch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;filter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hamburg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Graz&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;flightsResource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;httpResource&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Flight&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.example.com/flights&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;flights&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flightsResource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flightsResource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flightsResource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the template reacts automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;@if (flightsResource.isLoading()) {
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;Loading...&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
}

@for (flight of flightsResource.value(); track flight.id) {
  &lt;span class="nt"&gt;&amp;lt;app-flight-card&lt;/span&gt; &lt;span class="na"&gt;[item]=&lt;/span&gt;&lt;span class="s"&gt;"flight"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Race conditions are handled automatically — only the most recent request result is used, matching the behavior of &lt;code&gt;switchMap&lt;/code&gt; in RxJS.&lt;/p&gt;

&lt;h2&gt;
  
  
  The New &lt;code&gt;@Service&lt;/code&gt; Decorator
&lt;/h2&gt;

&lt;p&gt;One of the most elegant additions in Angular 22. The new &lt;code&gt;@Service&lt;/code&gt; decorator replaces the common &lt;code&gt;@Injectable({ providedIn: 'root' })&lt;/code&gt; pattern with something more intentional:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Service&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Provided in root by default&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FlightClient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Opt out of auto-providing&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;autoProvided&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TabRegistry&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;code&gt;injectAsync&lt;/code&gt; — Lazy Dependency Injection
&lt;/h2&gt;

&lt;p&gt;A brand new primitive: &lt;code&gt;injectAsync&lt;/code&gt; lets you inject dependencies lazily — only when they're actually needed. This is particularly powerful for heavy services, feature-specific dependencies, or anything you don't want loaded at startup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;[...]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ReportComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;getReportService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;injectAsync&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./report.service&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReportService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;generateReport&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getReportService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Combined with lazy-loaded routes, this gives you incredibly fine-grained control over what gets loaded and when.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;debounced()&lt;/code&gt; Signals
&lt;/h2&gt;

&lt;p&gt;A small but very practical addition — &lt;code&gt;debounced()&lt;/code&gt; wraps a signal and delays its notifications, perfect for search inputs and other high-frequency interactions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchTerm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;debouncedTerm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;debounced&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 300ms delay&lt;/span&gt;

&lt;span class="c1"&gt;// Use debouncedTerm in httpResource to avoid firing a request on every keystroke&lt;/span&gt;
&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;httpResource&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;q&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;debouncedTerm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No more manual &lt;code&gt;debounceTime&lt;/code&gt; in RxJS pipelines for this common pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  Incremental Hydration On by Default
&lt;/h2&gt;

&lt;p&gt;Angular 22 is also a serious security release, and most of the fixes apply automatically. The platform-server package guards against server-side request forgery (SSRF) and path hijacking, rejects suspicious and protocol-relative URLs, and closes SSRF bypasses through backslash URLs in HttpClient.&lt;/p&gt;

&lt;p&gt;On the SSR side, &lt;code&gt;provideClientHydration()&lt;/code&gt; now enables Incremental Hydration automatically. If you don't need it, opt out explicitly with &lt;code&gt;withNoIncrementalHydration()&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Angular AI Tooling
&lt;/h2&gt;

&lt;p&gt;Angular 22 announced Angular Aria is stable, and AI tooling has arrived. The Angular MCP Server — introduced in Angular 21 — continues to mature, enabling AI-assisted development workflows directly in tools like VS Code and Cursor. Think automatic migrations, intelligent code generation, and AI-powered refactoring that understands Angular's architecture.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Micro-Frontends with Angular: Is It Worth the Complexity?</title>
      <dc:creator>Placide</dc:creator>
      <pubDate>Sun, 19 Apr 2026 14:19:41 +0000</pubDate>
      <link>https://dev.to/rigole/micro-frontends-with-angular-is-it-worth-the-complexity-3pi</link>
      <guid>https://dev.to/rigole/micro-frontends-with-angular-is-it-worth-the-complexity-3pi</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Micro-frontends have gone from a niche architectural pattern to a buzzword every senior frontend developer is expected to have an opinion on. And if you're building with &lt;strong&gt;Angular&lt;/strong&gt;, you've probably wondered: should we go micro-frontend? Is it worth it? Where do we even start?&lt;br&gt;
This article gives you an honest, practical answer — including when to use them, when to run away, and how to implement them in Angular when the time is right.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Are Micro-Frontends?&lt;/strong&gt;&lt;br&gt;
Micro-frontends apply the principles of microservices to the frontend. Instead of one large Angular application, you split your UI into smaller, independently developed, deployed, and owned applications — each responsible for a specific business domain.&lt;/p&gt;

&lt;p&gt;Each micro-frontend (MFE) is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Developed independently by a dedicated team&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deployed on its own schedule&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Loaded dynamically into a shell application at runtime&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The Case For Micro-Frontends
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Independent deployment&lt;/strong&gt;: The biggest win. Team A can ship a fix to the Auth module without waiting for Team B to finish their Dashboard feature. No more deployment coordination nightmares.&lt;br&gt;
&lt;strong&gt;Team autonomy&lt;/strong&gt;: Each team owns their slice of the product end-to-end — from backend to frontend. This aligns perfectly with Conway's Law and reduces cross-team dependencies.&lt;br&gt;
&lt;strong&gt;Incremental migration&lt;/strong&gt;: If you're sitting on a legacy AngularJS or React app, micro-frontends let you migrate piece by piece to modern Angular — without a risky big-bang rewrite.&lt;br&gt;
&lt;strong&gt;Independent scaling of teams&lt;/strong&gt; :Onboarding a new team? Give them a bounded micro-frontend to own. They can work without needing to understand the entire codebase.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Real Costs Nobody Talks About
&lt;/h2&gt;

&lt;p&gt;Before you get excited, here's what production experience teaches you:&lt;br&gt;
&lt;strong&gt;Shared state is painful&lt;/strong&gt; :Micro-frontends are isolated by design. Sharing state between them — like the current user, a shopping cart, or global notifications — requires deliberate solutions: a shared event bus, a state management library exposed via the shell, or browser storage. None of these are elegant.&lt;br&gt;
&lt;strong&gt;CSS bleeds if you're not careful&lt;/strong&gt;: Without proper isolation (Shadow DOM, CSS Modules, or strict naming conventions), styles from one MFE can leak into another. This is a subtle but very real production problem.&lt;br&gt;
&lt;strong&gt;Bundle size can explode&lt;/strong&gt;: If each MFE bundles its own copy of Angular, RxJS, and other shared libraries, your users download the same code multiple times. Module Federation's shared dependencies solve this — but require careful configuration.&lt;br&gt;
&lt;strong&gt;Debugging across boundaries is harder&lt;/strong&gt;: Stack traces, error monitoring, and performance profiling become more complex when errors span multiple independently deployed applications.&lt;br&gt;
&lt;strong&gt;Operational overhead&lt;/strong&gt;: Instead of one CI/CD pipeline, you now have many. Instead of one deployment, you have many. This overhead is worth it at scale — but punishing for small teams.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to Implement Micro-Frontends in Angular
&lt;/h2&gt;

&lt;p&gt;The most mature approach today is Module Federation, available through two options:&lt;/p&gt;
&lt;h3&gt;
  
  
  Option 1: Webpack Module Federation**
&lt;/h3&gt;

&lt;p&gt;Angular CLI supports Module Federation via &lt;strong&gt;@angular-architects/module-federation&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng add @angular-architects/module-federation &lt;span class="nt"&gt;--project&lt;/span&gt; shell &lt;span class="nt"&gt;--port&lt;/span&gt; 4200 &lt;span class="nt"&gt;--type&lt;/span&gt; host
ng add @angular-architects/module-federation &lt;span class="nt"&gt;--project&lt;/span&gt; dashboard-mfe &lt;span class="nt"&gt;--port&lt;/span&gt; 4201 &lt;span class="nt"&gt;--type&lt;/span&gt; remote
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configure the remote in webpack.config.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// dashboard-mfe/webpack.config.js&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withModuleFederationPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dashboardMfe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;exposes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/app/dashboard/dashboard.module.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;share&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;singleton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;strictVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;singleton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;strictVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Load it in the shell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// shell/app.routes.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nf"&gt;loadRemoteModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;remoteEntry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:4201/remoteEntry.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;exposedModule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DashboardModule&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Option 2: Native Federation**
&lt;/h3&gt;

&lt;p&gt;A newer, Vite-compatible alternative from the same team:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng add @angular-architects/native-federation &lt;span class="nt"&gt;--project&lt;/span&gt; shell &lt;span class="nt"&gt;--port&lt;/span&gt; 4200 &lt;span class="nt"&gt;--type&lt;/span&gt; host
ng add @angular-architects/native-federation &lt;span class="nt"&gt;--project&lt;/span&gt; dashboard-mfe &lt;span class="nt"&gt;--port&lt;/span&gt; 4201 &lt;span class="nt"&gt;--type&lt;/span&gt; remote
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Native Federation works with Angular's modern ESBuild pipeline and is the recommended path for new projects in 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sharing State Between Micro-Frontends
&lt;/h2&gt;

&lt;p&gt;The most common challenge. Here are the three patterns ranked by simplicity:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Custom Events (simplest)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Emitting from MFE&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatchEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CustomEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user:updated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="c1"&gt;// Listening in shell or another MFE&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user:updated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CustomEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Shared Service via Shell
&lt;/h3&gt;

&lt;p&gt;Expose a singleton service from the shell and inject it into MFEs via a shared library.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. External State Store
&lt;/h3&gt;

&lt;p&gt;Use a lightweight external store (like a shared RxJS BehaviorSubject in a shared library) that all MFEs import as a singleton via Module Federation's shared config.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When Should You Actually Use Micro-Frontends?&lt;/strong&gt;&lt;br&gt;
Use them when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You have 3+ teams working on the same frontend product&lt;br&gt;
Different parts of your app need truly independent release cycles&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You are migrating a legacy app and need to run old and new code side by side&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your Angular monorepo has become genuinely unmanageable&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Skip them when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You have one team — use Nx or Angular libraries instead&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You want better code organization — NgModules or standalone component architecture solves this&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You're building an MVP or early-stage product — the overhead will slow you down&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your team is new to Angular — master the fundamentals first&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Alternatives Worth Considering
&lt;/h2&gt;

&lt;p&gt;Before going &lt;strong&gt;micro-frontend&lt;/strong&gt;, make sure you've explored:&lt;br&gt;
&lt;strong&gt;Nx Monorepo with Angular Libraries&lt;/strong&gt;:Nx gives you independent libraries, enforced boundaries, and separate build caching — solving most team-scale problems without the runtime complexity of micro-frontends.&lt;br&gt;
&lt;strong&gt;Standalone Components + Lazy Loading&lt;/strong&gt;:Angular's standalone components with granular lazy loading give you excellent code splitting and team separation without a micro-frontend architecture.&lt;br&gt;
These cover 80% of the use cases teams think they need micro-frontends for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Micro-frontends with Angular are a genuinely powerful pattern — but they come with real costs that are easy to underestimate. The technology is mature enough to use in production today, especially with Module Federation or Native Federation.&lt;br&gt;
But the honest truth is: most teams don't need them yet.&lt;br&gt;
Start with a well-structured Angular monorepo, enforce boundaries with Nx, and adopt lazy loading aggressively. When your team structure and deployment needs genuinely outgrow that — micro-frontends will be waiting for you.&lt;/p&gt;

&lt;p&gt;Have you shipped micro-frontends with Angular in production? What was your biggest challenge? Drop it in the comments! &lt;/p&gt;

</description>
      <category>angular</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Angular State Management in 2026: NgRx vs Signals vs Services — A Practical Comparison</title>
      <dc:creator>Placide</dc:creator>
      <pubDate>Sun, 15 Mar 2026 12:49:32 +0000</pubDate>
      <link>https://dev.to/rigole/angular-state-management-in-2026-ngrx-vs-signals-vs-services-a-practical-comparison-4doo</link>
      <guid>https://dev.to/rigole/angular-state-management-in-2026-ngrx-vs-signals-vs-services-a-practical-comparison-4doo</guid>
      <description>&lt;p&gt;Every Angular developer faces it eventually: your app grows, components need to share state, and suddenly you're asking — how should I manage this?&lt;br&gt;
In 2026, you have three solid options: plain Services, Angular Signals, and NgRx. Each has a sweet spot. This article breaks them down with real examples so you can make the right call for your project.&lt;/p&gt;
&lt;h2&gt;
  
  
  Option 1 — Services (The Classic Approach)
&lt;/h2&gt;

&lt;p&gt;Services with BehaviorSubject have been the go-to solution for years, and for good reason — they're simple, well-understood, and require zero extra dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CartService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;_items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
  &lt;span class="nx"&gt;items$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asObservable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;([...&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They are best for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Small to medium apps&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Teams already comfortable with RxJS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;State that lives in one or two places&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But be carefull because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;No dev tools or traceability&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can get messy as the app scales&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Easy to create inconsistencies across multiple services&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Option 2 — Signals (The Modern Default)
&lt;/h2&gt;

&lt;p&gt;Introduced in Angular 16 and now fully stable, Signals are Angular's built-in reactivity primitive. They eliminate most RxJS boilerplate for UI state and integrate natively with the template engine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CartService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;_items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
  &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asReadonly&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_items&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your template reacts automatically — no async pipe, no manual subscription:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;@for (item of cartService.items(); track item.id) {
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ item.name }} — {{ item.price }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
}
&lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;Total: {{ cartService.total() }}&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They are best for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;New Angular projects (17+)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Local and shared UI state&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Teams wanting to reduce RxJS complexity&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But be carefull because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Not ideal for complex async flows (RxJS still wins there)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Relatively new — fewer patterns established in large codebases&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Option 3 — NgRx (The Enterprise Powerhouse)
&lt;/h2&gt;

&lt;p&gt;NgRx implements the Redux pattern in Angular. Actions, reducers, selectors, effects — everything is explicit, traceable, and testable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Action&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[Cart] Add Item&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Item&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// Reducer&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cartReducer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createReducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}))&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Selector&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectCartItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;selectCartState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// In component&lt;/span&gt;
&lt;span class="nx"&gt;items$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selectCartItems&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Best for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Large enterprise apps&lt;/li&gt;
&lt;li&gt;Big teams needing shared conventions&lt;/li&gt;
&lt;li&gt;Complex async flows and side effects&lt;/li&gt;
&lt;li&gt;When you need full state history &amp;amp; debugging via Redux DevTools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Be carefull about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Significant boilerplate (NgRx Signals Store reduces this)&lt;/li&gt;
&lt;li&gt;Steep learning curve for newcomers&lt;/li&gt;
&lt;li&gt;Overkill for small/medium apps&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Side-by-Side Comparison
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Services&lt;/th&gt;
&lt;th&gt;Signals&lt;/th&gt;
&lt;th&gt;NgRx&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Boilerplate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Very Low&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Learning Curve&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scalability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Medium-High&lt;/td&gt;
&lt;td&gt;Very High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dev Tools&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Nope&lt;/td&gt;
&lt;td&gt;Nope&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Async Handling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;RxJS&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Effects&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best App Size&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Small&lt;/td&gt;
&lt;td&gt;Small–Medium&lt;/td&gt;
&lt;td&gt;Large&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  My Decision Framework
&lt;/h3&gt;

&lt;p&gt;Is your app small or a prototype?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Services or Signals&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Is your team new to Angular?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Signals (less to learn)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do you have complex async flows (websockets, polling, chained HTTP)?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NgRx Effects or RxJS in a Service&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Is your team large with multiple feature modules?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NgRx (with NgRx Signals Store to reduce boilerplate)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Can You Mix Them?&lt;br&gt;
Absolutely — and many real-world apps do. A common pattern is:&lt;/p&gt;

&lt;p&gt;Signals for local UI state (form state, toggles, UI flags)&lt;br&gt;
Services for simple shared state&lt;br&gt;
NgRx only for the most complex global state (auth, cart, notifications)&lt;/p&gt;

&lt;p&gt;Don't feel pressured to pick one and apply it everywhere.&lt;/p&gt;

&lt;p&gt;There's no single winner in Angular state management — the right tool depends on your app's complexity, your team's experience, and how much structure you need.&lt;br&gt;
My personal default in 2026: start with Signals, reach for NgRx only when the complexity demands it.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>This Trick That Made Me Understand signal() and computed() in Angular</title>
      <dc:creator>Placide</dc:creator>
      <pubDate>Sun, 18 Jan 2026 10:12:24 +0000</pubDate>
      <link>https://dev.to/rigole/this-trick-that-made-me-understand-signal-and-computed-in-angular-4odl</link>
      <guid>https://dev.to/rigole/this-trick-that-made-me-understand-signal-and-computed-in-angular-4odl</guid>
      <description>&lt;p&gt;When Angular introduced Signals, I was excited…&lt;br&gt;
but also confused.&lt;/p&gt;

&lt;p&gt;kept asking myself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;How is this different from Observables?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When should I use signal()?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Why do we need computed()?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Is this just another reactive API?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then one simple trick changed everything for me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Stop thinking in streams. Start thinking in state.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  The Mental Model Shift
&lt;/h2&gt;

&lt;p&gt;Here’s the trick:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;signal() = State&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;computed() = Derived State&lt;br&gt;
That’s it.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing more complicated.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;ts&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;doubleCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How to think about it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;count = the source of truth&lt;/li&gt;
&lt;li&gt;doubleCount = a calculation based on the truth&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just like real life:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You store raw data&lt;/li&gt;
&lt;li&gt;You derive insights from that data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why This Made Everything Clear&lt;/p&gt;

&lt;p&gt;signal()&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Holds state&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can be read&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can be updated&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Triggers updates automatically&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s your single source of truth.&lt;/p&gt;

&lt;p&gt;computed()&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Never stores state&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Only derives state&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Recalculates automatically&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Always stays in sync&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;doubleCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You never update computed() manually.&lt;br&gt;
It updates itself.&lt;br&gt;
The Big Realization&lt;/p&gt;

&lt;p&gt;Before, I was thinking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;subscriptions&lt;/li&gt;
&lt;li&gt;streams&lt;/li&gt;
&lt;li&gt;emissions&lt;/li&gt;
&lt;li&gt;operators&lt;/li&gt;
&lt;li&gt;pipes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now I think:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;state&lt;/li&gt;
&lt;li&gt;dependencies&lt;/li&gt;
&lt;li&gt;derivations&lt;/li&gt;
&lt;li&gt;reactivity graph&lt;/li&gt;
&lt;li&gt;automatic updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Signals are not trying to replace Observables.&lt;br&gt;
They are solving a different problem:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Simple, synchronous, local state management inside components.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;How This Changed My Angular Design&lt;/p&gt;

&lt;p&gt;Now I design components like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Signals → store state&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Computed → derive state&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Effects → react to state&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Observables → async flows / APIs / streams&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This separation makes my apps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;more predictable&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;easier to debug&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;easier to test&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;easier to scale&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;easier to reason about&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understanding Signals is not about learning new syntax.&lt;/p&gt;

&lt;p&gt;It’s about learning a new way to think:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Data - State - Derivation - Reaction&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you get that mental model,&lt;br&gt;
signal() and computed() become natural.&lt;/p&gt;

&lt;p&gt;And Angular suddenly feels… simpler&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Angular Signals vs Observables — What I Really Learned</title>
      <dc:creator>Placide</dc:creator>
      <pubDate>Sat, 10 Jan 2026 07:17:35 +0000</pubDate>
      <link>https://dev.to/rigole/angular-signals-vs-observables-what-i-really-learned-3dgh</link>
      <guid>https://dev.to/rigole/angular-signals-vs-observables-what-i-really-learned-3dgh</guid>
      <description>&lt;p&gt;When Angular introduced Signals, the community reaction was immediate.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Some were excited.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Some were confused.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Some assumed RxJS was on its way out.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After using both in real Angular applications, I realized something important:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signals don’t replace Observables — they clarify how we should think about state and reactivity.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This article isn’t about syntax.&lt;br&gt;
It’s about the mental shift Angular Signals introduced.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Core Difference
&lt;/h2&gt;

&lt;p&gt;At a high level:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Signals are about state&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Observables are about streams over time&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once I understood this, many design decisions became clearer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Signals Really Changed for Me
&lt;/h2&gt;

&lt;p&gt;Signals shine when dealing with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;local component state&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;derived values&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;template-driven reactivity&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;synchronous&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;explicit &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;easy to trace&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a signal changes, Angular knows exactly what to update.&lt;/p&gt;

&lt;p&gt;This made my components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;smaller&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;easier to reason about&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;less dependent on RxJS operators&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Signals encouraged me to keep UI state simple and intentional.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Observables Are Still Essential
&lt;/h2&gt;

&lt;p&gt;Observables remain the right tool for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;HTTP requests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;user events&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;WebSockets&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;async workflows&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They model time, not just values.&lt;/p&gt;

&lt;p&gt;Features like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;subscribe&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;switchMap&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;retry&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;debounceTime&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;are still critical in real-world applications.&lt;/p&gt;

&lt;p&gt;Trying to replace Observables with Signals in these scenarios only adds confusion&lt;/p&gt;

&lt;p&gt;The Most Important Lesson&lt;/p&gt;

&lt;p&gt;The real improvement wasn’t performance.&lt;br&gt;
It was &lt;strong&gt;clarity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of forcing RxJS everywhere, I now ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Is this state? ** Signal**&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Is this async over time?  &lt;strong&gt;Observable&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That single question improved: readability, maintainability,team communication&lt;/p&gt;

&lt;p&gt;How I Use Them Together&lt;br&gt;
In practice, I recommend:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;fetch data with Observables&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;convert results into Signals&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;let Signals drive the UI&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This combination feels natural and balanced.&lt;/p&gt;

&lt;p&gt;Angular didn’t remove power.&lt;br&gt;
It redistributed responsibility.&lt;/p&gt;

&lt;p&gt;Signals didn’t make Observables obsolete.&lt;br&gt;
They made Angular more honest about intent.&lt;/p&gt;

&lt;p&gt;And for me, &lt;strong&gt;that’s the real win&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>architecture</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Angular Is Opinionated — Here’s Why That Made Me a Better Developer</title>
      <dc:creator>Placide</dc:creator>
      <pubDate>Sun, 28 Dec 2025 08:24:51 +0000</pubDate>
      <link>https://dev.to/rigole/angular-is-opinionated-heres-why-that-made-me-a-better-developer-2lp3</link>
      <guid>https://dev.to/rigole/angular-is-opinionated-heres-why-that-made-me-a-better-developer-2lp3</guid>
      <description>&lt;p&gt;One of the most common criticisms of Angular is that it’s too opinionated.&lt;/p&gt;

&lt;p&gt;People say it’s restrictive.&lt;br&gt;
That it tells you how to do things instead of letting you decide.&lt;/p&gt;

&lt;p&gt;I used to see that as a weakness.&lt;/p&gt;

&lt;p&gt;Today, I see it as one of the main reasons Angular helped me grow—not just as a coder, but as a software engineer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Does “Opinionated” Really Mean?
&lt;/h2&gt;

&lt;p&gt;An opinionated framework provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;strong conventions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;strong conventions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;recommended patterns&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of asking  “How should we organize this?”&lt;br&gt;
 on every project, Angular already answers many of those questions for you.&lt;/p&gt;

&lt;p&gt;At first, this can feel uncomfortable.&lt;br&gt;
But over time, it becomes a powerful learning tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clear Project Structure
&lt;/h2&gt;

&lt;p&gt;Angular encourages a predictable structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Components for UI&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Services for business logic&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Modules and shared folders for organization&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;This consistency matters.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you open an Angular project—especially a large one—you immediately know where to look.&lt;br&gt;
New developers onboard faster, and the codebase feels intentional instead of improvised.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Structure reduces cognitive load.&lt;br&gt;
Less guessing = better focus.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Separation of Concerns
&lt;/h2&gt;

&lt;p&gt;Angular strongly pushes you to separate responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Components&lt;/strong&gt; handle presentation and interaction&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Services&lt;/strong&gt; handle logic, data access, and state&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Templates&lt;/strong&gt; focus on rendering&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This prevents components from turning into massive, unmaintainable files.&lt;/p&gt;

&lt;p&gt;The result : cleaner code, easier testing, safer refactoring&lt;br&gt;
Angular doesn’t force you to do this—but it makes the alternative painful enough that you quickly learn why separation matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consistent Patterns Across the Codebase
&lt;/h2&gt;

&lt;p&gt;Angular promotes consistency through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Dependency injection&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lifecycle hooks&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Input/output communication&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standardized tooling&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When everyone follows the same patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Code reviews are faster&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Collaboration improves&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Bugs become easier to spot&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of debating styles and architectures, teams can focus on delivering value.&lt;/p&gt;

&lt;p&gt;Consistency is underrated—but it’s a superpower in team environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Predictable Architecture at Scale
&lt;/h2&gt;

&lt;p&gt;As applications grow, chaos becomes expensive.&lt;/p&gt;

&lt;p&gt;Angular’s opinions lead to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Predictable data flow&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Safer refactoring&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Clearer boundaries&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This predictability gives you confidence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;to change features&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;to clean old code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;to scale without fear&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you trust the architecture, you move faster—even in complex systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Angular Really Taught Me
&lt;/h2&gt;

&lt;p&gt;Angular didn’t just teach me syntax or APIs.&lt;/p&gt;

&lt;p&gt;It taught me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;to respect structure&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;to think long-term&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;to value consistency over cleverness&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;to understand that constraints can be guidance&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the real world, software isn’t written once—it’s maintained, extended, and shared.&lt;/p&gt;

&lt;p&gt;Angular prepares you for that reality.&lt;/p&gt;

&lt;p&gt;Opinionated frameworks aren’t about limiting developers.&lt;br&gt;
They’re about protecting teams and codebases from chaos.&lt;/p&gt;

&lt;p&gt;Angular made me a better developer because it forced me to slow down, think, and build with intention.&lt;/p&gt;

&lt;p&gt;Sometimes, the best freedom comes from good constraints.&lt;/p&gt;

&lt;p&gt;Let's connect on &lt;a href="https://www.linkedin.com/in/placide-rigole-foleu-155904125/" rel="noopener noreferrer"&gt;linkedIn&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>angular</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Why Angular Templates Make You a Better Developer (Not Just a Better Coder)</title>
      <dc:creator>Placide</dc:creator>
      <pubDate>Sat, 22 Nov 2025 12:51:29 +0000</pubDate>
      <link>https://dev.to/rigole/why-angular-templates-make-you-a-better-developer-not-just-a-better-coder-n1f</link>
      <guid>https://dev.to/rigole/why-angular-templates-make-you-a-better-developer-not-just-a-better-coder-n1f</guid>
      <description>&lt;p&gt;When developers talk about Angular, most conversations revolve around architecture, TypeScript, dependency injection, RxJS, signals, or modules.&lt;br&gt;
But there’s one part of Angular that silently shapes the way you think—&lt;strong&gt;templates&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Angular templates are not just HTML with extra syntax.&lt;br&gt;
They are a discipline.&lt;br&gt;
A mindset.&lt;br&gt;
A way of expressing logic clearly and intentionally.&lt;/p&gt;

&lt;p&gt;Over time, I realized something important:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you can keep your templates clean, you can keep your entire codebase clean.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here’s why Angular templates make you a better developer.&lt;/p&gt;
&lt;h2&gt;
  
  
  1. They Force Clear Separation of Concerns
&lt;/h2&gt;

&lt;p&gt;Angular templates naturally push you to separate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;UI logic&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Business logic&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;State management&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Anything &lt;strong&gt;heavy&lt;/strong&gt; must be moved to the component or a service.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Mixing logic in the template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{{ products.filter(p =&amp;gt; p.inStock &lt;span class="err"&gt;&amp;amp;&amp;amp;&lt;/span&gt; p.price &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt; &lt;span class="err"&gt;20).&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt; &lt;span class="err"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clean separation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;inStockProducts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inStock&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{{ inStockProducts.length }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Templates reward clarity and punish complexity — a core engineering skill.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. You Learn to Think in Terms of State
&lt;/h2&gt;

&lt;p&gt;Templates are state-driven.&lt;/p&gt;

&lt;p&gt;If your UI breaks, it’s usually because your state is unclear or inconsistent.&lt;/p&gt;

&lt;p&gt;Angular pushes you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Keep your state predictable&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use inputs and outputs properly&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Structure your data so it flows cleanly through the UI&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the foundation of scalable front-end development — no matter the framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Directives Teach You to Write Declarative UI
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;*ngIf, *ngFor, ngClass, ngStyle…&lt;/em&gt;&lt;br&gt;
These teach you to express intent instead of implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;*ngIf=&lt;/span&gt;&lt;span class="s"&gt;"isLoggedIn"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Welcome!&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don’t tell Angular how to show the element.&lt;br&gt;
You simply declare:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Show it when this condition is true.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s the essence of modern frontend engineering.&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Pipes Make You Think More Functionally
&lt;/h2&gt;

&lt;p&gt;Pipes encourage transforming data in a clean, reusable way.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{{ price | currency:'USD' }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of hiding formatting logic deep inside components, Angular hands you a better way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Focused&lt;/li&gt;
&lt;li&gt;Reusable&lt;/li&gt;
&lt;li&gt;Testable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s functional programming made visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Clean Templates = Clean Components
&lt;/h2&gt;

&lt;p&gt;If your template becomes messy, it reveals deeper issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;too much responsibility&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;unclear state&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;poor architecture&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Angular templates are like a mirror reflecting your thought process.&lt;/p&gt;

&lt;p&gt;A clean template means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;your component is focused&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;your logic is modular&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;your architecture is solid&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words…&lt;br&gt;
&lt;strong&gt;your development habits are healthy&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Angular templates are more than a tool — they are an instructor.&lt;br&gt;
They quietly teach you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;clarity&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;structure&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;discipline&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;predictable thinking&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And these are the qualities that make someone not just a coder…&lt;br&gt;
&lt;strong&gt;But a software engineer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you’re learning Angular, don’t just learn the syntax.&lt;br&gt;
Learn the mindset it encourages.&lt;br&gt;
Because mastering templates means mastering the way you think about UI, state, and architecture.&lt;/p&gt;

&lt;p&gt;Want more posts like this?&lt;/p&gt;

&lt;p&gt;I also share my technical content on &lt;a href="https://www.linkedin.com/in/placide-rigole-foleu-155904125/" rel="noopener noreferrer"&gt;LinkedIn — feel free to connect!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>architecture</category>
      <category>angular</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Angular Isn’t Just About Code — It’s About Discipline</title>
      <dc:creator>Placide</dc:creator>
      <pubDate>Sun, 09 Nov 2025 07:22:15 +0000</pubDate>
      <link>https://dev.to/rigole/angular-isnt-just-about-code-its-about-discipline-2k47</link>
      <guid>https://dev.to/rigole/angular-isnt-just-about-code-its-about-discipline-2k47</guid>
      <description>&lt;p&gt;When I started learning &lt;strong&gt;Angular&lt;/strong&gt;, my goal was simple: make things work.&lt;br&gt;
I was obsessed with getting components to render, data to flow, and routes to connect.&lt;/p&gt;

&lt;p&gt;But as I grew more comfortable, I started to notice something subtle — Angular wasn’t just teaching me to code better. It was teaching me to think better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture Forces You to Think in Systems
&lt;/h2&gt;

&lt;p&gt;In Angular, nothing stands alone.&lt;br&gt;
Every service, module, and component fits into a larger ecosystem. You quickly learn that architecture matters — that the way you structure your code impacts how easily it scales, how readable it is for others, and how fast you can add new features later.&lt;/p&gt;

&lt;p&gt;This mindset shift helped me stop writing “quick fixes” and start designing for the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependency Injection Teaches You Separation of Concerns
&lt;/h2&gt;

&lt;p&gt;Angular’s dependency injection system might seem complex at first — but it’s actually a lesson in clean design.&lt;/p&gt;

&lt;p&gt;It forces you to think:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Should this logic really live here?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By keeping your components lean and delegating responsibilities to services, you start building modular, testable, and maintainable codebases — the kind of projects teams love to work in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lifecycle Hooks Teach You Awareness
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;ngOnInit, ngOnDestroy, ngAfterViewInit&lt;/strong&gt; — they’re not just methods, they’re reminders of how your app behaves over time.&lt;/p&gt;

&lt;p&gt;Angular helps you become aware of what happens before, during, and after your components exist.&lt;br&gt;
That level of awareness translates into writing more predictable, controlled code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Strong Typing and Templates Encourage Discipline
&lt;/h2&gt;

&lt;p&gt;Combine Angular with TypeScript, and suddenly, “anything goes” doesn’t work anymore.&lt;br&gt;
You have to define, type, and think before you act.&lt;/p&gt;

&lt;p&gt;This structure prevents chaos. It teaches patience. It rewards consistency.&lt;br&gt;
And that’s what discipline is all about.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Lesson
&lt;/h2&gt;

&lt;p&gt;Angular isn’t just a front-end framework.&lt;br&gt;
It’s a framework that cultivates professional habits.&lt;/p&gt;

&lt;p&gt;It teaches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;How to respect structure&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How to think in patterns&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How to communicate through code&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The same habits that make a good Angular developer often make a good software engineer in general.&lt;/p&gt;

&lt;p&gt;If you’re learning &lt;strong&gt;Angular&lt;/strong&gt; today, don’t just focus on syntax.&lt;br&gt;
Focus on how it trains your mind — to write cleaner, think clearer, and build smarter.&lt;/p&gt;

&lt;p&gt;Because at the end of the day,** Angular** isn’t just about code — it’s about discipline.&lt;/p&gt;

&lt;p&gt;You can find me sharing more Angular lessons and experiences here and on my &lt;a href="https://www.linkedin.com/in/placide-rigole-foleu-155904125/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Angular #WebDevelopment #SoftwareEngineering #TypeScript #CleanCode #DeveloperMindset
&lt;/h1&gt;

</description>
      <category>angular</category>
      <category>architecture</category>
      <category>learning</category>
    </item>
    <item>
      <title>What Working with People from Different Backgrounds Taught Me as a #Developer</title>
      <dc:creator>Placide</dc:creator>
      <pubDate>Sun, 26 Oct 2025 13:01:03 +0000</pubDate>
      <link>https://dev.to/rigole/what-working-with-people-from-different-backgrounds-taught-me-as-a-developer-5d8c</link>
      <guid>https://dev.to/rigole/what-working-with-people-from-different-backgrounds-taught-me-as-a-developer-5d8c</guid>
      <description>&lt;p&gt;When we talk about being a developer, we often focus on frameworks, programming languages, and new tools.&lt;br&gt;
But one of the most valuable experiences I’ve had in my journey hasn’t come from code — it came from people.&lt;/p&gt;

&lt;p&gt;Working with teammates from different &lt;strong&gt;countries&lt;/strong&gt;, &lt;strong&gt;cultures&lt;/strong&gt;, and &lt;strong&gt;backgrounds&lt;/strong&gt; has changed the way I &lt;strong&gt;think&lt;/strong&gt;, &lt;strong&gt;build&lt;/strong&gt;, and &lt;strong&gt;collaborate&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Different Backgrounds Mean Different Perspectives
&lt;/h2&gt;

&lt;p&gt;When you work in an international or multicultural team, you quickly realize there isn’t just one right way to solve a problem.&lt;br&gt;
People think differently because their education systems, work cultures, and life experiences shape how they approach challenges.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;And that’s where innovation starts.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sometimes, a teammate from another country proposes a solution I never would’ve imagined — not because it’s technically better, but because they see the problem differently.&lt;/p&gt;

&lt;p&gt;It taught me to stay &lt;strong&gt;open-minded and listen before speaking&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Communication Is a Skill, Not an Assumption
&lt;/h2&gt;

&lt;p&gt;When you work with people who don’t share your first language, you quickly learn the importance of clarity.&lt;br&gt;
You start thinking about how to explain your ideas in simple, clear ways.&lt;/p&gt;

&lt;p&gt;I realized that being a good communicator is not about speaking a lot — &lt;strong&gt;&lt;em&gt;it’s about making sure others truly understand what you mean&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This skill has made me a better teammate and even improved how I write documentation and commit messages.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Empathy Builds Stronger Teams
&lt;/h2&gt;

&lt;p&gt;In multicultural environments, &lt;strong&gt;empathy becomes essential&lt;/strong&gt;.&lt;br&gt;
Not everyone has the same comfort zone, sense of humor, or approach to teamwork.&lt;/p&gt;

&lt;p&gt;By taking time to understand why someone acts or communicates a certain way, you build trust — and &lt;strong&gt;&lt;em&gt;trust makes collaboration smoother than any project management tool ever could.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Tech Is Global — and So Are We
&lt;/h2&gt;

&lt;p&gt;Whether you work in Angular, React, or Node.js, &lt;strong&gt;&lt;em&gt;technology connects us beyond borders.&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
Our code might live in GitHub repos, but &lt;strong&gt;&lt;em&gt;our ideas come from everywhere&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That’s why cultural diversity isn’t just “nice to have” — it’s a competitive advantage.&lt;/p&gt;

&lt;p&gt;Working with people from different countries has taught me that diversity is not a challenge — &lt;strong&gt;it’s a strength&lt;/strong&gt;.&lt;br&gt;
Every time we share our unique perspectives, &lt;strong&gt;&lt;em&gt;we grow — not only as developers, but as humans&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The best code doesn’t just come from one mind.&lt;br&gt;
It comes from many** minds thinking together**.&lt;/p&gt;

&lt;p&gt;I’m sharing more about my journey as a developer — from technical lessons in Angular to reflections on teamwork and growth.&lt;br&gt;
You can also find me on &lt;a href="https://www.linkedin.com/in/placide-rigole-foleu-155904125/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; where I share regular posts about development and personal growth in tech.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
      <category>angular</category>
    </item>
    <item>
      <title>Mastering Angular Lifecycle Hooks — The Hidden Superpowers</title>
      <dc:creator>Placide</dc:creator>
      <pubDate>Wed, 22 Oct 2025 09:53:28 +0000</pubDate>
      <link>https://dev.to/rigole/mastering-angular-lifecycle-hooks-the-hidden-superpowers-21jb</link>
      <guid>https://dev.to/rigole/mastering-angular-lifecycle-hooks-the-hidden-superpowers-21jb</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.tourl"&gt;&lt;/a&gt;Hey everyone. I’m Placide (&lt;a class="mentioned-user" href="https://dev.to/rigole"&gt;@rigole&lt;/a&gt;), a full-stack developer passionate about &lt;strong&gt;Angular, TypeScript&lt;/strong&gt;, &lt;strong&gt;Java&lt;/strong&gt; And &lt;strong&gt;Python&lt;/strong&gt;(Yeah that could be a lot but with passion you do not count).&lt;/p&gt;

&lt;p&gt;When I first started using &lt;strong&gt;Angular&lt;/strong&gt;, I thought lifecycle hooks were just “fancy methods” that Angular called automatically. But as I got experiences and grew more comfortable with the framework, I realized they’re actually the heartbeat of every Angular component. Understanding them can help you control how your app behaves from creation to destruction — and make your code much cleaner and more predictable.&lt;br&gt;
Let’s dive in. Shall we ?&lt;/p&gt;
&lt;h2&gt;
  
  
  What Are Lifecycle Hooks ?
&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;Angular&lt;/strong&gt;, &lt;strong&gt;lifecycle hooks&lt;/strong&gt; are special methods that allow you to tap into key moments of a component’s life — from the moment it’s created, to when it’s updated, to when it’s destroyed.&lt;br&gt;
Each hook represents a specific stage of the component’s “lifecycle.”&lt;/p&gt;

&lt;p&gt;Here’s the full sequence:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ngOnChanges → ngOnInit → ngDoCheck → ngAfterContentInit&lt;br&gt;
→ ngAfterContentChecked → ngAfterViewInit → ngAfterViewChecked → ngOnDestroy&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
It seems a lot but don’t worry — you don’t need all of them.&lt;br&gt;
Let’s look at the ones you’ll use most often:&lt;/p&gt;
&lt;h2&gt;
  
  
  ngOnInit() — Initialization Magic
&lt;/h2&gt;

&lt;p&gt;This is one of the most commonly used hooks.&lt;br&gt;
It runs once, right after Angular initializes all data-bound properties.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductListComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;products&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadProducts&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;loadProducts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;watches&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;phones&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Pro tip: Keep your initialization logic here — not in the constructor because the constructor should only handle dependency injection, not side effects.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ngOnChanges() — Reacting to Input Changes
&lt;/h2&gt;

&lt;p&gt;Whenever a parent component updates an @Input() -A post about it is coming.We are going to talk about reusable component- value, Angular triggers &lt;strong&gt;ngOnChanges()&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductDetailsComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnChanges&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;productName&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnChanges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SimpleChanges&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;productName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Product Name changed:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;productName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;currentValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Pro tip: Perfect for components that depend on dynamic input data (e.g., updating details when a user is selected).&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ngOnDestroy() — The Cleanup Hero
&lt;/h2&gt;

&lt;p&gt;This hook runs right before the component is destroyed.&lt;br&gt;
It’s the best place to clean up anything that could cause memory leaks, like subscriptions or timers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChatComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Subscription&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chatService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Chat component destroyed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Pro tip: Always clean up your observables and DOM listeners here.&lt;br&gt;
You’ll thank yourself later.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  ngAfterViewInit() — The View Is Ready
&lt;/h2&gt;

&lt;p&gt;This hook is called after Angular initializes the component’s view and child views.&lt;br&gt;
Use it for working with @ViewChild()-Articles is coming too- references or DOM elements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DashboardComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;AfterViewInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ViewChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;chart&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ElementRef&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;ngAfterViewInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Pro tip: If you try to access @ViewChild() before this hook, it’ll be undefined so be carefull&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Lifecycle Hooks Matter
&lt;/h2&gt;

&lt;p&gt;Lifecycle hooks are more than just Angular internals — they’re tools that help you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Improve component reusability and testing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Understand how Angular manages your app’s state&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Write cleaner, more predictable code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoid memory leaks&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understanding Angular’s lifecycle hooks is like learning how the engine of your car works.&lt;br&gt;
You don’t need to be an expert mechanic, but knowing when to accelerate, pause, and stop makes you a better driver — and a better Angular developer.&lt;/p&gt;

&lt;p&gt;If you found this useful, I share more tips like this on my LinkedIn — feel free to connect with me there! &lt;a href="https://www.linkedin.com/in/placide-rigole-foleu-155904125/" rel="noopener noreferrer"&gt;Here is the link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What’s your favorite lifecycle hook, and how has it helped you write cleaner Angular code?&lt;br&gt;
Drop it in the comments — I’d love to learn from your experience too.&lt;/p&gt;

&lt;h1&gt;
  
  
  Angular #TypeScript #WebDevelopment #Frontend #DevelopersJourney #CodingTips
&lt;/h1&gt;

</description>
      <category>webdev</category>
      <category>angular</category>
      <category>learning</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
