<?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>Forem: Evgeniy OZ</title>
    <description>The latest articles on Forem by Evgeniy OZ (@oz).</description>
    <link>https://forem.com/oz</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F178622%2F7fad92e1-b6ee-495e-8e86-dfb231a74e0f.jpg</url>
      <title>Forem: Evgeniy OZ</title>
      <link>https://forem.com/oz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/oz"/>
    <language>en</language>
    <item>
      <title>Reactivity in Angular</title>
      <dc:creator>Evgeniy OZ</dc:creator>
      <pubDate>Wed, 18 Jun 2025 08:42:03 +0000</pubDate>
      <link>https://forem.com/oz/reactivity-in-angular-b84</link>
      <guid>https://forem.com/oz/reactivity-in-angular-b84</guid>
      <description>&lt;p&gt;This article explains why we should build our Angular apps with reactivity in mind and how immutability helps with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Magic
&lt;/h2&gt;

&lt;p&gt;Look at this 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="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;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
        &amp;lt;div&amp;gt;Name: {{user.name}}&amp;lt;/div&amp;gt;
        &amp;lt;div&amp;gt;Age: {{user.age}}&amp;lt;/div&amp;gt;

         &amp;lt;button (click)="updateName()"&amp;gt;Set Random Name&amp;lt;/button&amp;gt;
         &amp;lt;button (click)="updateAge()"&amp;gt;Set Random Age&amp;lt;/button&amp;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;App&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;user&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;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nf"&gt;updateName&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;i&lt;/span&gt; &lt;span class="o"&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="nx"&gt;names&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;names&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="p"&gt;}&lt;/span&gt;

      &lt;span class="nf"&gt;updateAge&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;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&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;20&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;20&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;iframe src="https://stackblitz.com/edit/stackblitz-starters-edq9u6rq?ctl=1&amp;amp;embed=1&amp;amp;file=src%2Fmain.ts&amp;amp;hideExplorer=1&amp;amp;hideNavigation=1&amp;amp;theme=dark" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;It works, but it only works because of magic. Dark magic. I wish it didn’t work :) What’s much worse is that code like this is scattered across Angular tutorials for beginners, so it shouldn’t be surprising that many Angular apps have similar code, and that many readers right now are asking, “What the hell is wrong with this code, dude? It just works. Chill, man.”&lt;/p&gt;

&lt;h3&gt;
  
  
  What works
&lt;/h3&gt;

&lt;p&gt;In our template, we have bindings:&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&amp;gt;&lt;/span&gt;Name: {{user.name}}&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;Age: {{user.age}}&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;When &lt;code&gt;user.name&lt;/code&gt; changes, Angular reflects this change and updates the HTML element. That seems quite reasonable and logical.&lt;/p&gt;

&lt;p&gt;But how does Angular know that &lt;code&gt;user.name&lt;/code&gt; has changed? We didn’t call anything like &lt;code&gt;heyAngularWeChangedTheUserObject()&lt;/code&gt; or even &lt;code&gt;checkBindingsPlease()&lt;/code&gt;. This is where the dark magic hides — and this magic has its price.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the price
&lt;/h3&gt;

&lt;p&gt;The magic tricks here are “dirty checking” and “monkey patching”.&lt;/p&gt;

&lt;p&gt;They hurt performance and can cause data pollution (undesired mutations) in non-trivial apps. But they work just fine in small apps, especially in the simple examples provided in tutorials.&lt;/p&gt;

&lt;p&gt;To cast the “dirty checking” spell, Angular has to check every binding (and every “input”) in every component of your application. Some of these components are used in “for” loops, some are reused multiple times, so the number of rendered components might be higher than the total number of components your app has.&lt;/p&gt;

&lt;p&gt;And Angular doesn’t know &lt;strong&gt;&lt;em&gt;when&lt;/em&gt;&lt;/strong&gt; your bindings might change. So Angular reacts to every change of every &lt;code&gt;[input]&lt;/code&gt; and &lt;code&gt;(output)&lt;/code&gt; and DOM event listeners like (click). And still, it is not enough.&lt;/p&gt;

&lt;p&gt;Data in your app might change asynchronously. Not right after the &lt;code&gt;(output)&lt;/code&gt; has emitted (for example), but a little bit later, after loading some data. And Angular will run its dirty checking too early to notice the changes.&lt;/p&gt;

&lt;p&gt;For that, Angular uses another spell: “monkey patching.”&lt;/p&gt;

&lt;p&gt;A special tool, Zone.js, wraps asynchronous APIs like &lt;code&gt;setTimeout&lt;/code&gt;, &lt;code&gt;requestAnimationFrame&lt;/code&gt;, &lt;code&gt;Promise&lt;/code&gt;, &lt;code&gt;MutationObserver&lt;/code&gt;, and events like &lt;code&gt;click&lt;/code&gt;, &lt;code&gt;change&lt;/code&gt;, &lt;code&gt;mousemove&lt;/code&gt;, and many others [1]. So when they are called, Zone.js notifies Angular — and that’s how it knows when to cast the “dirty checking” spell.&lt;/p&gt;

&lt;h3&gt;
  
  
  Did you just say mousemove?
&lt;/h3&gt;

&lt;p&gt;Yes. And &lt;code&gt;scroll&lt;/code&gt; is also patched. Now you can imagine how many times Angular has to check every binding in your components.&lt;/p&gt;

&lt;p&gt;The existence of this dark magic led to a special rule:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Thou shalt not call functions in your templates! ☝️&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even beginners know this rule, because it’s practically a commandment in many tutorials.&lt;/p&gt;

&lt;p&gt;The reason: comparing two variables by reference is a very &lt;em&gt;cheap&lt;/em&gt; operation in terms of performance. But if a binding involves a function, that function will be called, and computing its value might not be so cheap.&lt;/p&gt;

&lt;p&gt;This rule is nothing but an adaptation to the shortcomings of the dark magic we just explored.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is the OnPush Change Detection Strategy Enough?
&lt;/h3&gt;

&lt;p&gt;There are two change detection strategies in Angular that components can use, and one of them, &lt;code&gt;OnPush&lt;/code&gt;, instructs the framework to check not every component in the app, but only the modified component and its ancestors.&lt;/p&gt;

&lt;p&gt;But just changing the strategy in an existing component is not enough. First, every binding should be reactive — otherwise, we’ll do more harm than good.&lt;/p&gt;

&lt;p&gt;Let’s modify our example a bit:&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="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;OnPush&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;

      &lt;span class="nf"&gt;updateAge&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Any asynchronous code.&lt;/span&gt;
        &lt;span class="c1"&gt;// Imagine we are loading the allowed ages list.&lt;/span&gt;
        &lt;span class="nf"&gt;setTimeout&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="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&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;70&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&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="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;iframe src="https://stackblitz.com/edit/stackblitz-starters-qzs61s3o?ctl=1&amp;amp;embed=1&amp;amp;file=src%2Fmain.ts&amp;amp;hideExplorer=1&amp;amp;hideNavigation=1&amp;amp;theme=dark" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Now, if you click “Set Age” first, you will see no changes. But if you click “Set Name” afterwards, you’ll see both the name and the age updated.&lt;/p&gt;

&lt;p&gt;Explanation of the bug:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When we click the button, the event handler not only calls &lt;code&gt;updateAge()&lt;/code&gt;, but also marks our component as “dirty” and schedules a Change Detection cycle;&lt;/li&gt;
&lt;li&gt;Change Detection runs, but can’t see any changes because they will be applied later (asynchronously). It removes the “dirty” mark from our component;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;setTimeout()&lt;/code&gt; is patched by Zone.js, so after 1ms, it schedules a Change Detection cycle;&lt;/li&gt;
&lt;li&gt;Change Detection runs, but our component has the &lt;code&gt;OnPush&lt;/code&gt; strategy and is not marked as “dirty” (see step &lt;em&gt;2&lt;/em&gt;), so the component is skipped;&lt;/li&gt;
&lt;li&gt;When we click another button, the event handler calls &lt;code&gt;updateName()&lt;/code&gt;, marks our component as dirty, and schedules a Change Detection cycle;&lt;/li&gt;
&lt;li&gt;Change Detection runs and sees changes in both of our bindings: &lt;code&gt;user.name&lt;/code&gt;, which we just changed, and &lt;code&gt;user.age&lt;/code&gt;, which we changed previously. Both changes are then reflected.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is an example of why we should not use OnPush with non-reactive bindings.&lt;br&gt;
We should only use &lt;code&gt;OnPush&lt;/code&gt; when every binding in our template is reactive.&lt;/p&gt;

&lt;p&gt;As you can see from the steps &lt;em&gt;3&lt;/em&gt; and &lt;em&gt;4&lt;/em&gt;, Zone.js can notify the framework about &lt;strong&gt;&lt;em&gt;when&lt;/em&gt;&lt;/strong&gt;, but not &lt;strong&gt;&lt;em&gt;where&lt;/em&gt;&lt;/strong&gt; a change detection is required.&lt;/p&gt;

&lt;p&gt;Angular is moving away from black magic. In the Zone.js repo, you can find [2]:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As Angular moves towards a zoneless application development model, Zone.js is no longer accepting new features, including additional patches for native platform APIs. The team will also not be accepting any low priority bug fixes. Any critical bug fixes that relate to Angular’s direct use of Zone.js will still be accepted.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And this is the direction we all should move as well — towards…&lt;/p&gt;
&lt;h2&gt;
  
  
  Pure Reactivity
&lt;/h2&gt;

&lt;p&gt;If we notify the framework that some parts of our templates have changed, then the framework will not need all that dark magic and can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check only the modified parts;&lt;/li&gt;
&lt;li&gt;Only when needed;&lt;/li&gt;
&lt;li&gt;Optimize DOM updates even with asynchronous changes;&lt;/li&gt;
&lt;li&gt;Stop using monkey patching.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It might sound too good to be true, but we can do this already — starting with Angular version 20! We’ll need 3 things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;bindings in our templates should use only Signals;&lt;/li&gt;
&lt;li&gt;every component should use &lt;code&gt;OnPush&lt;/code&gt; change detection strategy;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;provideZonelessChangeDetection()&lt;/code&gt; in &lt;code&gt;bootstrapApplication()&lt;/code&gt; providers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If, for some reason, you can’t use Angular v20 yet, or some old libraries are not compatible with zoneless change detection — don’t worry. If you can use Signals for bindings (or at least the async pipe with Observables), and all your components use the &lt;code&gt;OnPush&lt;/code&gt; change detection strategy, the performance of your app will be quite close to that of a zoneless app.&lt;/p&gt;

&lt;p&gt;An additional benefit of a zoneless app: it &lt;strong&gt;&lt;em&gt;forces&lt;/em&gt;&lt;/strong&gt; your code not to rely on Zone.js and to be purely reactive.&lt;/p&gt;
&lt;h3&gt;
  
  
  Reactive bindings
&lt;/h3&gt;

&lt;p&gt;The point of reactive bindings is to notify Angular about the changes (when and where they happened), so Angular can react (pun intended) and reflect the changes with minimal performance costs.&lt;/p&gt;

&lt;p&gt;Let’s fix our bug by replacing our non-reactive bindings with reactive ones:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/stackblitz-starters-gmo6eqde?ctl=1&amp;amp;embed=1&amp;amp;file=src%2Fmain.ts&amp;amp;hideExplorer=1&amp;amp;hideNavigation=1&amp;amp;theme=dark" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Let’s analyze our code:&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="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-root&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;OnPush&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&amp;gt;Name: {{name()}}&amp;lt;/div&amp;gt;
        &amp;lt;div&amp;gt;Age: {{age()}}&amp;lt;/div&amp;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;App&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;user&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;User&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;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;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="nx"&gt;name&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;user&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;age&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;user&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nf"&gt;updateName&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;i&lt;/span&gt; &lt;span class="o"&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="nx"&gt;names&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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;user&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;user&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;user&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="nx"&gt;names&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="p"&gt;}));&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nf"&gt;updateAge&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setTimeout&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="nx"&gt;user&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;user&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;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;age&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;70&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;20&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;1&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;Now &lt;code&gt;user&lt;/code&gt; is a signal, we have two derived (computed) signals: &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;age&lt;/code&gt;, and our &lt;code&gt;updateName()&lt;/code&gt; and &lt;code&gt;updateAge()&lt;/code&gt; methods have been modified a little.&lt;/p&gt;

&lt;p&gt;Every time we modify the &lt;code&gt;user&lt;/code&gt; signal, it sends notifications to &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;age&lt;/code&gt;, and they send notifications to the template. &lt;br&gt;
When this happens, the template marks our component as “dirty” and schedules a Change Detection cycle.&lt;/p&gt;

&lt;p&gt;Without any magic, we let Angular know where and when changes happened, so Angular can granularly update only the needed parts — and only when it’s needed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;But wait, we are calling functions in our template! 😱&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yes, and it’s ok. Signals are functions, but their call is super cheap because they don’t compute their value on every call. They memoize their value, so calling them doesn’t hurt performance. &lt;br&gt;
In fact, any function that memoizes its value can be safely called from the template [3]. Signals just guarantee this out of the box.&lt;/p&gt;
&lt;h3&gt;
  
  
  Immutability
&lt;/h3&gt;

&lt;p&gt;In the &lt;code&gt;updateName()&lt;/code&gt; and &lt;code&gt;updateAge()&lt;/code&gt; methods, we use the &lt;code&gt;update()&lt;/code&gt; method of an Angular Signal and create a shallow copy of the existing object. Why not just mutate the fields of the existing object?&lt;/p&gt;

&lt;p&gt;Because when we update an Angular Signal using &lt;code&gt;set()&lt;/code&gt; or &lt;code&gt;update()&lt;/code&gt;, Angular compares the new value with the old one. A notification will be sent only if they are not equal. And they are compared by reference (&lt;code&gt;===&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Two references to the same object are always considered equal — and that’s why we create a shallow copy: to trigger the value change notification.&lt;/p&gt;

&lt;p&gt;You can verify this behavior in the following new methods:&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;mutateAge&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;user&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="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&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;70&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;mutateAgeAndSet&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;user&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="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&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;70&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;20&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;user&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;user&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;In &lt;code&gt;mutateAge()&lt;/code&gt;, we mutate the field of a signal value. As you can check, this will not work.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;mutateAgeAndSet()&lt;/code&gt;, we mutate the field and call the signal’s &lt;code&gt;set()&lt;/code&gt; method. It will compare two user objects, they are equal by reference, so this will not trigger any changes either.&lt;/p&gt;

&lt;p&gt;You can read more about Angular Signals reactivity and mutations in my other article [4].&lt;/p&gt;

&lt;p&gt;There is an easy trick to protect ourselves from this mistake:&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;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="na"&gt;name&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="k"&gt;readonly&lt;/span&gt; &lt;span class="na"&gt;age&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are more advanced tools to provide immutability, but this one doesn’t require any libraries to use.&lt;/p&gt;

&lt;p&gt;Immutability is not only helpful for reactivity. It has other benefits: your data will not be polluted (modified by code that has no clue it’s modifying shared data), it protects from unexpected side effects, and it makes testing easier.&lt;/p&gt;

&lt;p&gt;It is possible to override the default equality check function in Angular Signals (in most of their kinds), but you should only do this in exceptional cases, when providing the new values in an immutable way is more expensive than checking equality manually. &lt;br&gt;
Checking equality in nested objects recursively can be quite expensive in terms of performance and might require special handling if the objects have circular references.&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance
&lt;/h3&gt;

&lt;p&gt;Let’s explore why the &lt;em&gt;Signals in Templates&lt;/em&gt; + &lt;em&gt;OnPush&lt;/em&gt; + &lt;em&gt;Zoneless&lt;/em&gt; formula provides the best possible performance for your Angular app.&lt;/p&gt;

&lt;p&gt;A template is a consumer of signals and behaves similarly to &lt;code&gt;effect()&lt;/code&gt;, but it also schedules a Change Detection cycle when a signal is updated.&lt;/p&gt;

&lt;p&gt;Unlike the &lt;code&gt;async&lt;/code&gt; pipe [9], the template will not be triggered on every update of the signal. As we learned above, only non-equal values will trigger an update. &lt;br&gt;
Also, if a signal is updated 100 times synchronously (each time with a new value), the template will schedule just one Change Detection cycle.&lt;/p&gt;

&lt;p&gt;Here is the difference in how Observables and Signals deliver their update notifications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Observables emit every time we ask them to. They don’t check if the next value is equal to the previous one. 
When an Observable emits a value, the subscriber must handle it, because it can’t predict whether there will be another. 
We could use &lt;code&gt;debounceTime(0)&lt;/code&gt;, but that would introduce unnecessary asynchrony when a synchronous update would be sufficient;&lt;/li&gt;
&lt;li&gt;Consumers of signals receive only a notification about the update, not the new value. To get the new value, they must read the updated signal — and they are free to do this whenever they want. In the case of computed signals, this means that the new value will be recomputed not at the moment when the signals used in the computation are updated, but when the consumer reads the value of that computed signal. This can eliminate a lot of unnecessary computations, because consumers (&lt;code&gt;effect()&lt;/code&gt;, templates) schedule the reads of the signals they are subscribed to, so they don’t read more often than needed. You can read more about signals timings in the article linked below [6].&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the &lt;code&gt;OnPush&lt;/code&gt; strategy is combined with signals (your template uses only signals for reactivity and all components use the &lt;code&gt;OnPush&lt;/code&gt; strategy), Angular applies an optimization called “&lt;strong&gt;Local Change Detection&lt;/strong&gt;” [5]. It doesn’t mark every ancestor as “dirty”; instead, it marks only the component as “dirty” and marks each ancestor “for traversal.” &lt;br&gt;
This means that non-dirty ancestors will not be checked.&lt;/p&gt;

&lt;p&gt;And when every binding (that can change) in our templates uses a signal, we simply don’t need Zone.js and its performance overhead — Angular already knows where and when changes happened.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Combined with the “Single Source of Truth” and “Template First” approaches ([7], [8]), this article will help you create super-performant, declarative, and scalable code. **To the stars! 🚀&lt;/em&gt;**&lt;/p&gt;

&lt;h3&gt;
  
  
  Links:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;“&lt;a href="https://github.com/angular/angular/blob/main/packages/zone.js/STANDARD-APIS.md" rel="noopener noreferrer"&gt;Zone.js’s support for standard apis&lt;/a&gt;” (&lt;a href="https://github.com/angular/angular/blob/2e3925a65ce4280f8b31c4f8184666880d03acae/packages/zone.js/STANDARD-APIS.md" rel="noopener noreferrer"&gt;permalink&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;“&lt;a href="https://github.com/angular/angular/blob/main/packages/zone.js/README.md#development-status-of-zonejs" rel="noopener noreferrer"&gt;Development Status of Zone.js&lt;/a&gt;” (&lt;a href="https://github.com/angular/angular/blob/2e3925a65ce4280f8b31c4f8184666880d03acae/packages/zone.js/README.md#development-status-of-zonejs" rel="noopener noreferrer"&gt;permalink&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;“&lt;a href="https://dev.to/this-is-angular/its-ok-to-use-function-calls-in-angular-templates-4029"&gt;It’s ok to use function calls in Angular templates!&lt;/a&gt;” by Enea Jahollari.&lt;/li&gt;
&lt;li&gt;“&lt;a href="https://dev.to/oz/angular-signals-keeping-the-reactivity-train-582o"&gt;Angular Signals: Keeping the Reactivity Train&lt;/a&gt;”.&lt;/li&gt;
&lt;li&gt;“&lt;a href="https://itnext.io/onpush-and-signals-local-change-detection-in-angular-17-c70e830fd209" rel="noopener noreferrer"&gt;Local Change Detection in Angular 17&lt;/a&gt;” by Ilir Beqiri.&lt;/li&gt;
&lt;li&gt;“&lt;a href="https://dev.to/oz/angular-signals-timing-4njh"&gt;Angular Signals — Timing&lt;/a&gt;”.&lt;/li&gt;
&lt;li&gt;“&lt;a href="https://dev.to/oz/angular-inputs-and-single-source-of-truth-4kog"&gt;Angular Inputs and Single Source of Truth&lt;/a&gt;”.&lt;/li&gt;
&lt;li&gt;“&lt;a href="https://dev.to/oz/creating-angular-components-template-first-declarative-approach-pai"&gt;Creating Angular Components: Template-First Declarative Approach&lt;/a&gt;”.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackblitz.com/edit/stackblitz-starters-9hrznumk?file=src%2Fmain.ts" rel="noopener noreferrer"&gt;StackBlitz, example with async pipe&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackblitz.com/edit/stackblitz-starters-edq9u6rq?file=src%2Fmain.ts" rel="noopener noreferrer"&gt;StackBlitz, example 1&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackblitz.com/edit/stackblitz-starters-qzs61s3o?file=src%2Fmain.ts" rel="noopener noreferrer"&gt;StackBlitz, example 2&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackblitz.com/edit/stackblitz-starters-gmo6eqde?file=src%2Fmain.ts" rel="noopener noreferrer"&gt;StackBlitz, example 3&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>angular</category>
    </item>
    <item>
      <title>Examples of linkedSignal() usage in Angular applications</title>
      <dc:creator>Evgeniy OZ</dc:creator>
      <pubDate>Mon, 09 Jun 2025 16:00:52 +0000</pubDate>
      <link>https://forem.com/oz/examples-of-linkedsignal-usage-in-angular-applications-1oof</link>
      <guid>https://forem.com/oz/examples-of-linkedsignal-usage-in-angular-applications-1oof</guid>
      <description>&lt;p&gt;Angular 20 has been released, linkedSignal() is now stable, and I want to share my experience using this powerful function.&lt;/p&gt;

&lt;h2&gt;
  
  
  The main use case
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;linkedSignal()&lt;/code&gt; is a perfect tool when you want to compute some initial value, then let the user modify it, and still keep it in a reactive signal.&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;CategoriesComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;categories&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;Category&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;selectedCategory&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;categories&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;pickCategory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Category&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;selectedCategory&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;cat&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;How it works: the initial value of the &lt;code&gt;selectedCategory&lt;/code&gt; signal will be computed as &lt;code&gt;this.categories()[0]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;this.categories&lt;/code&gt; is a signal, and every time this signal changes, &lt;code&gt;selectedCategory&lt;/code&gt; will be re-computed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Technically, it is a bit more complicated: &lt;code&gt;linkedSignal()&lt;/code&gt; will not re-compute its value at the moment when any of the signals it consumes notifies about a possible change, but rather when a consumer of the &lt;code&gt;linkedSignal()&lt;/code&gt; reads it and the &lt;code&gt;linkedSignal()&lt;/code&gt; has unchecked notifications about changes. However, stating this every time would make it much more difficult to read.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those who are familiar with &lt;code&gt;computed()&lt;/code&gt; might say that &lt;code&gt;linkedSignal()&lt;/code&gt; works the same, but there are two important differences between them.&lt;/p&gt;

&lt;p&gt;Look at the &lt;code&gt;pickCategory()&lt;/code&gt; method: Here we set the new value for the &lt;code&gt;selectedCategory&lt;/code&gt; signal, and this value will remain until the &lt;code&gt;categories&lt;/code&gt; signal “emits” a new value — then &lt;code&gt;selectedCategory&lt;/code&gt; will be recomputed again, and the value we previously set in that method will be overridden.&lt;/p&gt;

&lt;p&gt;It is very useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;displaying pre-computed forms (using previously saved data or default values) and letting the user change the values (to save them later, or just to affect other parts of the app);&lt;/li&gt;
&lt;li&gt;pages where the initial properties should be loaded from the API or default values, not the URL, and the URL cannot be the source of truth (large tables with filters and pagination, games, 3D scenes), and the user is supposed to modify the values;&lt;/li&gt;
&lt;li&gt;components where one input control might restrict the range of allowed values of other input controls. For example, a date picker where the user picks the year, month, and date separately;&lt;/li&gt;
&lt;li&gt;computed (derived) signals that should know the previously computed value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that is the second important difference: &lt;code&gt;linkedSignal()&lt;/code&gt; not only returns a &lt;code&gt;WritableSignal&lt;/code&gt;, but also lets us use the previous value.&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;VehiclesComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;showAtv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;linkedSignal&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="p"&gt;,&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="na"&gt;source&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;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasATVInfo&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;computation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;previous&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="nx"&gt;source&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="p"&gt;{&lt;/span&gt;
            &lt;span class="cm"&gt;/**
             * If other fields of the form were changed and
             * we no longer have ATV vehicle info,
             * but we are displaying it as "yes,"
             * leave it as "yes" - do not reset this switch.
             * Otherwise, the opened form will be unexpectedly
             * (for the user) closed, and the user might still
             * want to edit this form, bringing in the new ATV info.
             */&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;previous&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="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="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;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;source&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;Sometimes you don’t need a &lt;code&gt;WritableSignal&lt;/code&gt;, and you would like to use &lt;code&gt;computed()&lt;/code&gt;, but you absolutely need the previous value to compute the new one, even if &lt;code&gt;computed()&lt;/code&gt; is supposed to be pure. It’s not an idiomatic example, but for these exceptional cases, you can use this trick:&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;Example&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;someInput&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="nx"&gt;myComputedSignal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;linkedSignal&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="p"&gt;,&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="na"&gt;source&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;someInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;computation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;previous&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="nx"&gt;previous&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SOME VALUE&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="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SOMETHING ELSE&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;source&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;asReadOnly&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;- and it's not writable anymore&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  With great power…
&lt;/h2&gt;

&lt;p&gt;When we have more than one source of truth, things become less declarative and less safe. We should use &lt;code&gt;linkedSignal()&lt;/code&gt; with care.&lt;/p&gt;

&lt;p&gt;Look at this example:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/stackblitz-starters-u9zk1qmn?ctl=1&amp;amp;embed=1&amp;amp;file=src%2Fmain.ts&amp;amp;hideExplorer=1" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;If a user doesn’t want to be named “Goblin,” they will enter something else, for example, “Wizard.” Now they see in the form that their favorite color is Green and their nickname is “Wizard.” But their favorite color is purple, they input “Purple,” and now they are named “Purple Goblin.” Not an expected behavior, to say the least!&lt;/p&gt;

&lt;p&gt;In this form, after “nickname” was edited, it should not be derived (computed) anymore.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;code&gt;linkedSignal()&lt;/code&gt; is a wonderful tool that can be extremely useful sometimes. Happy coding!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>angular</category>
    </item>
    <item>
      <title>Starting a Modern Angular Application</title>
      <dc:creator>Evgeniy OZ</dc:creator>
      <pubDate>Sun, 16 Feb 2025 09:20:59 +0000</pubDate>
      <link>https://forem.com/oz/starting-a-modern-angular-application-34h6</link>
      <guid>https://forem.com/oz/starting-a-modern-angular-application-34h6</guid>
      <description>&lt;p&gt;The initial architecture of a web application is fundamentally important — it will affect your app for multiple years, impacting not only development but also the user experience. Things like lazy loading, bundle size, icon reuse, and other small details will influence the user experience, not just CI time, code reuse, or the onboarding process.&lt;/p&gt;

&lt;p&gt;In this article, I’ll review the tools and options we have when creating a new Angular app and which of them, in my opinion, should be chosen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workspace
&lt;/h2&gt;

&lt;p&gt;So the first thing we should create is a “workspace”. We should decide what structure our application will have — where all the components, services, and other things will be located.&lt;/p&gt;

&lt;p&gt;Let’s discuss 3 ways of creating an initial structure:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Using Angular CLI, without separation by sub-modules/packages/libraries;&lt;/li&gt;
&lt;li&gt;Using Angular CLI to create a monorepo, all the code is in libraries;&lt;/li&gt;
&lt;li&gt;Using Nx to create a monorepo.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are other tools to create a monorepo, but that would take another article to describe them all :)&lt;/p&gt;

&lt;p&gt;So let’s compare what pros and cons every option has:&lt;/p&gt;

&lt;h3&gt;
  
  
  Angular CLI, without separation by sub-modules/packages/libraries
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Very easy to follow. Developers of any level can create a new component in the correct folder;&lt;/li&gt;
&lt;li&gt;No additional dependencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Very fragile because of tight coupling. Imports use relative paths: &lt;code&gt;import { NavbarComponent } from '../../../shared-components/navbar/navbar.component'&lt;/code&gt;, and if something is moved or renamed, many dependent components/services might need an update. A smart IDE can help with this, but not with a 100% guarantee. Moving and renaming things become dangerous;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Easy to create circular dependencies and ruin lazy-loading. See the example below;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lack of modularity. Moving some code to a separate library requires enormous effort in checking dependencies, and often this task remains forever in the backlog, with functionality just being copy-pasted to another app or project;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;test&lt;/code&gt;, &lt;code&gt;lint&lt;/code&gt;, and &lt;code&gt;build&lt;/code&gt; will always handle all the code you have. The more code you have, the longer these commands take, even if only one line in one component was changed;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Upgrades of tools like linters are not handled by &lt;code&gt;ng update&lt;/code&gt; - configs will remain the same, even if a linter or test runner library has a major version upgrade and requires modifications in configs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example of how the lazy-loading can be broken with this structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Component A imports Component B&lt;/li&gt;
&lt;li&gt;Component B imports Service S and Component C&lt;/li&gt;
&lt;li&gt;Component D imports Component A and Component B&lt;/li&gt;
&lt;li&gt;When any component imports just a single Component D, every part listed above is imported as well. This happens very often in real apps. Ruining a lazy-loading is especially easy with this structure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Angular CLI to create a monorepo, all the code is in libraries
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modular. Every library can be reused by multiple apps or even moved to its own repo and published to a registry. Then, it can be added to dependencies with 0 changes required in the code of other apps/libraries (because all imports are already non-relative);&lt;/li&gt;
&lt;li&gt;No additional dependencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every time you create a library you’ll need to manually modify the paths in tsconfig.json, because Angular CLI will generate paths to dist folder, so to get updates from any library, you need to build it first. And because all of the code is libraries, that would be a nightmare in ng serve mode, so you’ll change the path in tsconfig to the &lt;code&gt;public-api.ts&lt;/code&gt; file of a library you created&lt;/li&gt;
&lt;li&gt;No module boundaries tracking. Developers should create a document that explains the connections across modules to avoid circular dependencies. This document should be kept up to date and strictly followed every time a developer creates a library. There are tools such as &lt;em&gt;&lt;a href="https://www.npmjs.com/package/madge" rel="noopener noreferrer"&gt;madge&lt;/a&gt;&lt;/em&gt; which help with this, but they still should be run manually.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;test&lt;/code&gt;, &lt;code&gt;lint&lt;/code&gt;, and &lt;code&gt;build&lt;/code&gt; will always build every existing library and app. The more code you have, the longer these commands take, even if only one line in one library was changed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;test&lt;/code&gt;, &lt;code&gt;lint&lt;/code&gt;, and &lt;code&gt;build&lt;/code&gt; can only run consecutively, handling one library/app per run.&lt;/li&gt;
&lt;li&gt;Upgrades of tools like linters are not handled by &lt;code&gt;ng update&lt;/code&gt; - configs will remain the same, even if a linter or test runner library has a major version upgrade and requires modifications in configs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Using Nx to create a monorepo.
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modular. Every library can be reused by multiple apps or even moved to its own repo and published to a registry. Then, it can be added to dependencies with 0 changes required in the code of other apps/libraries (because all imports are already non-relative).&lt;/li&gt;
&lt;li&gt;Easy to configure e2e-testing with Playwright (comes out of the box with Nx).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;test&lt;/code&gt;, &lt;code&gt;lint&lt;/code&gt;, and &lt;code&gt;build&lt;/code&gt; will:&lt;/li&gt;
&lt;li&gt;handle libraries in parallel (the more cores your machine has, the sooner all the steps will be completed);&lt;/li&gt;
&lt;li&gt;only run for modified code — if just one library is modified, just that library will be linted and tested;&lt;/li&gt;
&lt;li&gt;use local cache — if code is not changed, results will be reused, even if commands are executed for all libraries (this behavior can be modified with &lt;code&gt;--skipNxCache&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Nx automatically &lt;a href="https://nx.dev/features/enforce-module-boundaries#project-apis" rel="noopener noreferrer"&gt;controls&lt;/a&gt; module boundaries.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nx migrate&lt;/code&gt; updates configs of linters and test runners when their version is updated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nx as an additional dependency.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can &lt;a href="https://nx.dev/blog/virtuous-cycle-of-workspace-structure" rel="noopener noreferrer"&gt;read here&lt;/a&gt; how Nx recommends organizing your workspace.&lt;/p&gt;

&lt;p&gt;There is also an excellent article, “&lt;a href="https://nx.dev/blog/managing-ts-packages-in-monorepos" rel="noopener noreferrer"&gt;Managing TypeScript Packages in Monorepos&lt;/a&gt;”.&lt;/p&gt;

&lt;p&gt;What you choose from these options is up to you. My recommendations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do not pick option 1, even if your app is small and you’re intimidated by the amount of boilerplate that other options bring — you’ll generate it once and forget about it;&lt;/li&gt;
&lt;li&gt;If you decide that the maintenance cost of the Nx dependency is too high compared to the benefits it provides, use option 2, and you can add Nx later. If you go this route, &lt;a href="https://angular.dev/reference/configs/file-structure#multiple-projects" rel="noopener noreferrer"&gt;generate a multi-project workspace&lt;/a&gt; — switching from a single-project to a multi-project workspace might take more time than expected, but doing it from the start will cost you nothing;&lt;/li&gt;
&lt;li&gt;I recommend option 3, as it significantly improves maintenance (not only of your code but also of your tools) and reduces generated boilerplate.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Style
&lt;/h2&gt;

&lt;p&gt;First of all, use &lt;a href="https://tailwindcss.com/docs/" rel="noopener noreferrer"&gt;Tailwind CSS&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;It is an excellent tool. If your team is more familiar with Bootstrap, it might be difficult to make the switch, but consider this argument: at the time of writing, Tailwind CSS has more than twice the &lt;a href="https://www.npmjs.com/package/tailwindcss" rel="noopener noreferrer"&gt;weekly downloads&lt;/a&gt; on npm &lt;a href="https://www.npmjs.com/package/bootstrap" rel="noopener noreferrer"&gt;than Bootstrap&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You’ll also need UI components (date picker, tabs, and so on). Here we have a lot of libraries, you can easily find them. Some of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://primeng.org/" rel="noopener noreferrer"&gt;PrimeNG&lt;/a&gt;: has a lot of components, can be styled using CSS variables, and has a plugin for Tailwind CSS support;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://material.angular.io/" rel="noopener noreferrer"&gt;Angular Material&lt;/a&gt;: has a lot of components and tools, can be styled using CSS variables (including the variables generated by Tailwind CSS), maintained by the Angular team, and they put a lot of effort into supporting accessibility features;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.spartan.ng/documentation/installation" rel="noopener noreferrer"&gt;spartan/ui&lt;/a&gt;: based on TailwindCSS, not so many components, in alpha stage;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://daisyui.com/" rel="noopener noreferrer"&gt;daysiUI&lt;/a&gt;: framework-agnostic, based on Tailwind CSS.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you wonder why some libraries you know and love are not on this list, the answer is “for brevity” - enlisting them all would be pointless when we have so many search tools.&lt;/p&gt;

&lt;p&gt;When picking a library, I recommend checking the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If it can be styled using CSS variables;&lt;/li&gt;
&lt;li&gt;If it doesn’t require additional dependencies, that are maintained by someone else;&lt;/li&gt;
&lt;li&gt;If Angular is the only JS part that it requires;&lt;/li&gt;
&lt;li&gt;If it’s popular and actively maintained.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the tool you picked asks you what format of CSS files you want, pick CSS — Tailwind works better with CSS, and in modern browsers, CSS can do things that were implemented only in SASS before, like nesting or variables.&lt;/p&gt;

&lt;h2&gt;
  
  
  SSR
&lt;/h2&gt;

&lt;p&gt;When the workspace generator asks you if you want SSR, answer “yes” even if you are 100% sure your app will never use Server Side Rendering.&lt;/p&gt;

&lt;p&gt;The code you write should be compatible with SSR anyway. Because when you want to reuse some of the libraries you created for this app, you might be surprised how much effort and how many breaking changes are required to make the existing code compatible with SSR. And if you turn on SSR mode for the &lt;code&gt;serve&lt;/code&gt; command, you’ll quickly learn what things to avoid to make code SSR compatible, and it will cost you nothing to write such code from the beginning.&lt;/p&gt;

&lt;p&gt;If your app doesn’t need SSR, you can just set &lt;code&gt;"ssr": false&lt;/code&gt; in the configuration file for the &lt;code&gt;build&lt;/code&gt; command and forget about it. But your code will still be reusable in any app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Standalone
&lt;/h2&gt;

&lt;p&gt;Modern Angular and Nx will generate standalone components, directives, pipes, and libraries by default, without &lt;code&gt;NgModule&lt;/code&gt;. Do not try to change it — this is the direction the framework is moving towards, and creating NgModules at this point is pointless. There are still modules, of course, in the libraries and the framework itself, and you’ll use them, just don’t create new modules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reactivity
&lt;/h2&gt;

&lt;p&gt;You are creating a new app, so it should use the latest features of Angular and be aligned with the trends in Angular evolution. Create a “zoneless” application. At the time of writing this article, it means that you’ll have to add &lt;code&gt;provideExperimentalZonelessChangeDetection()&lt;/code&gt; to your list of providers in the application config.&lt;/p&gt;

&lt;p&gt;Don’t be afraid of the “experimental” part — it works very well, even in the most complicated cases, and it might only require some workarounds if the libraries you use have usages of &lt;code&gt;NgZone.onMicrotaskEmpty&lt;/code&gt;, &lt;code&gt;NgZone.onUnstable&lt;/code&gt;, and &lt;code&gt;NgZone.onStable&lt;/code&gt;. Because you are creating a new app, the chances of encountering such cases are low, as Angular is moving toward zoneless architecture, and libraries will support it. Right now, if a library supports the &lt;code&gt;OnPush&lt;/code&gt; strategy and doesn’t use the methods of NgZone mentioned above, such a library is fully compatible with “zoneless” Angular apps.&lt;/p&gt;

&lt;p&gt;If your app is zoneless, every component has a change detection strategy &lt;code&gt;OnPush&lt;/code&gt; and you use &lt;em&gt;only signals&lt;/em&gt; in your template — Angular will benefit you with the best possible performance. And in the future, such apps will get even more performance optimizations in the framework core.&lt;/p&gt;

&lt;h2&gt;
  
  
  State Management
&lt;/h2&gt;

&lt;p&gt;I’ve built multiple apps using the approach explained in this article of mine: &lt;a href="https://medium.com/@eugeniyoz/application-state-management-with-angular-signals-b9c8b3a3afd7" rel="noopener noreferrer"&gt;Application State Management with Angular Signals&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you feel that your app is going to be quite complicated and you don’t think &lt;code&gt;createEffect()&lt;/code&gt; and signals will be enough — I would recommend giving a try to &lt;a href="https://ngrx.io/guide/signals/signal-store" rel="noopener noreferrer"&gt;SignalStore&lt;/a&gt; — some professionals I know and respect use this library and love it.&lt;/p&gt;

&lt;p&gt;That's it, you definitely will not need more complicated solutions.&lt;/p&gt;

&lt;p&gt;And, of course, I recommend my libraries as helpers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/e-oz/ngx-collection" rel="noopener noreferrer"&gt;Collection&lt;/a&gt; for managing the state of lists/collections;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/e-oz/ngx-reactive-storage" rel="noopener noreferrer"&gt;Reactive Storage&lt;/a&gt; for synchronizing data across tabs/windows using Signals, Observables, or Promises.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;For e2e, I recommend &lt;a href="https://playwright.dev/" rel="noopener noreferrer"&gt;Playwright&lt;/a&gt;, and if your team really loves to test things — &lt;a href="https://storybook.js.org/" rel="noopener noreferrer"&gt;Storybook&lt;/a&gt; (in addition).&lt;/p&gt;

&lt;p&gt;For unit tests, I recommend &lt;a href="https://vitest.dev/" rel="noopener noreferrer"&gt;Vitest&lt;/a&gt;. If you prefer something else — pick a tool that runs tests in a real browser (headless). That makes a huge difference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Strict TypeScript + Linters
&lt;/h2&gt;

&lt;p&gt;Here are options in tsconfig I use as basis and recommend for your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"strict"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;DO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;remove&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'emitDecoratorMetadata'!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'@typescript-eslint/consistent-type-imports'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;rule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;requires&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;it&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"emitDecoratorMetadata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"importHelpers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"noFallthroughCasesInSwitch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"noImplicitAny"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"noImplicitThis"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"noImplicitReturns"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"noImplicitOverride"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"noUnusedLocals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"noUnusedParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"strictNullChecks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"strictPropertyInitialization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"useUnknownInCatchVariables"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"noPropertyAccessFromIndexSignature"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"angularCompilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"strictInjectionParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"strictInputAccessModifiers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"strictTemplates"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"strictStandalone"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"fullTemplateTypeCheck"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"enableI18nLegacyMessageIdFormat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"disableTypeScriptVersionCheck"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"extendedDiagnostics"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"checks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"optionalChainNotNullable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"suppress"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"nullishCoalescingNotNullable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"suppress"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"suffixNotSupported"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"warning"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"textAttributeNotBinding"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"warning"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"invalidBananaInBox"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"missingControlFlowDirective"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"missingNgForOfLet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"controlFlowPreventingContentProjection"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"unusedStandaloneImports"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"warning"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"defaultCategory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s not the whole config, just options related to code check.&lt;/p&gt;

&lt;p&gt;And ESLint rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'no-extra-boolean-cast':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'no-case-declarations':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'@typescript-eslint/consistent-type-exports':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'@typescript-eslint/consistent-type-imports':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'@typescript-eslint/ban-ts-comment':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'off'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'@typescript-eslint/no-explicit-any':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'@typescript-eslint/no-non-&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="err"&gt;-assertion':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'@typescript-eslint/no-unused-vars':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;argsIgnorePattern:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'^_'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;varsIgnorePattern:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'^_'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;caughtErrorsIgnorePattern:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'^_'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'rxjs-angular-x/prefer-takeuntil':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;checkComplete:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;checkDecorators:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'Component'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'Directive'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'Injectable'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;alias:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'takeUntilDestroyed'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;checkDestroy:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'rxjs/ban-observables':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'rxjs/ban-operators':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'rxjs/no-connectable':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'rxjs/no-cyclic-action':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'rxjs/no-compat':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'rxjs/no-ignored-replay-buffer':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'rxjs/no-unsafe-catch':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'rxjs/no-unsafe-first':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'rxjs/no-unsafe-switchmap':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'rxjs/no-async-subscribe':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'rxjs/no-create':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'rxjs/no-ignored-observable':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'rxjs/no-exposed-subjects':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'rxjs/no-nested-subscribe':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'rxjs/no-ignored-notifier':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'rxjs/no-redundant-notify':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'rxjs/no-subject-unsubscribe':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'rxjs/no-unbound-methods':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'rxjs/no-unsafe-subject-next':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'rxjs/no-unsafe-takeuntil':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;eqeqeq:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'smart'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'prefer-const':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'no-unused-expressions':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'@angular-eslint/use-lifecycle-interface':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'@angular-eslint/no-input-rename':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'off'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'@angular-eslint/no-empty-lifecycle-method':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Plugins for RxJS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/@smarttools/eslint-plugin-rxjs" rel="noopener noreferrer"&gt;@smarttools/eslint-plugin-rxjs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/eslint-plugin-rxjs-angular-x" rel="noopener noreferrer"&gt;eslint-plugin-rxjs-angular-x&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As always, linters’ rules are a very opinionated thing, but if you are looking for an initial setup — this will be helpful and will help you avoid a lot of errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Immutability
&lt;/h2&gt;

&lt;p&gt;Make your data structures immutable by default. Don’t expect that your view will be updated because you mutated some field of a large structure — that contradicts how Angular change detection works, so it’s the wrong approach.&lt;/p&gt;

&lt;p&gt;Reactivity in Angular works best with Signals, and Signals compare their values by reference (you can change it, but deep checks are expensive and not always safe). This means that you need to create a new value for a signal every time you want to see any changes in your view.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://medium.com/@eugeniyoz/mastering-angular-essential-code-organization-principles-c09838dea6e2#19bc" rel="noopener noreferrer"&gt;this article&lt;/a&gt; of mine, you can read more about how to implement the simplest kind of immutability without any additional tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nice Little Things
&lt;/h2&gt;

&lt;p&gt;If you haven’t tried it yet, try &lt;code&gt;mat-icon&lt;/code&gt; from Angular Material + &lt;a href="https://material.angular.io/components/icon/overview#registering-icons" rel="noopener noreferrer"&gt;icons registry&lt;/a&gt;. The SVG will be inlined, so you can affect currentColor and set CSS variables, which opens up a lot of possibilities. It is much better than icon fonts — you are not limited by a predefined set of images and can use literally any image you want, even with animations (for some very fancy cases). And they look sharper :)&lt;/p&gt;

&lt;p&gt;Nice source of SVG icons: &lt;a href="https://lucide.dev/icons/" rel="noopener noreferrer"&gt;Lucide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/sindresorhus/type-fest" rel="noopener noreferrer"&gt;type-fest&lt;/a&gt; is a great tool that will add 0 bytes to your bundle.&lt;/p&gt;

&lt;p&gt;Try &lt;a href="https://www.npmjs.com/package/tailwindcss-safe-area" rel="noopener noreferrer"&gt;tailwindcss-safe-area&lt;/a&gt; if you care about how your app looks in landscape mode on mobile devices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things to Avoid
&lt;/h2&gt;

&lt;p&gt;Some Angular features might stay here for a while, but will not be actively developed. I recommend avoiding the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Angular Animations — use CSS animations instead. Yes, “leave” animations can’t be replaced, but that’s the only thing;&lt;/li&gt;
&lt;li&gt;Old control flow directives: &lt;code&gt;ngIf&lt;/code&gt;, &lt;code&gt;ngSwitch*&lt;/code&gt;, and, especially &lt;code&gt;ngFor&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;If you use Angular Material, only style it using CSS variables, do not create CSS rules with their class names in selectors. It might cause very painful breaking changes.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;That’s what I use to create super-performant modern Angular apps. I hope this information will be useful for your awesome apps as well!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>tailwindcss</category>
      <category>nx</category>
      <category>ssr</category>
    </item>
    <item>
      <title>Improving Code Reusability in Angular Projects</title>
      <dc:creator>Evgeniy OZ</dc:creator>
      <pubDate>Mon, 06 May 2024 11:34:54 +0000</pubDate>
      <link>https://forem.com/oz/improving-code-reusability-in-angular-projects-11bc</link>
      <guid>https://forem.com/oz/improving-code-reusability-in-angular-projects-11bc</guid>
      <description>&lt;p&gt;In this article, you’ll find recommendations on how to make your Angular components and services more reusable, maintainable, and scalable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pure Functions
&lt;/h3&gt;

&lt;p&gt;The most effective way to make your code reusable is to move as much code as possible to &lt;a href="https://en.wikipedia.org/wiki/Pure_function"&gt;pure functions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Such functions have no side effects, have no state, and don’t mutate their arguments. Every time we call a pure function with the same arguments, it will return the same result.&lt;/p&gt;

&lt;p&gt;Let’s refactor a component’s method into a pure 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;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleComponent&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;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="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;

      &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Output&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;new&lt;/span&gt; &lt;span class="nx"&gt;EventEmitter&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="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="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;errEmptyItemMsg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Item data can not be empty&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="c1"&gt;//...&lt;/span&gt;

      &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nf"&gt;addConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toItem&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;toItem&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="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;displayError&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;errEmptyItemMsg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;hasNewConnection&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;for &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;user&lt;/span&gt; &lt;span class="k"&gt;of&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;users&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;itemRefs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;itemRefs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;hasNewConnection&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="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;hasNewConnection&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;connected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toItem&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;private&lt;/span&gt; &lt;span class="nf"&gt;displayError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errMsg&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="c1"&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;Method &lt;code&gt;addConnection()&lt;/code&gt; validates toItem, then adds a new item ID to every user. It can display an error and emit an event.&lt;/p&gt;

&lt;p&gt;Let’s imagine that this method has not 18 lines, but 180, with complex validation rules. And suddenly, we need exactly this logic, with exactly the same validation (or a new data construction) in a completely different module of our application. Do not look at the “Copy” and “Paste” menu items in your editor — if validation logic is changed in one place, it should be modified in every other place.&lt;/p&gt;

&lt;p&gt;Even if we were to swear to update this code in every place on every change, it’s still tightly coupled to our component. So, we simply cannot copy this code to any other place without also copying dependent parts of the component. You can easily spot this by looking for the usages of this.:&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;displayError&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;errEmptyItemMsg&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;users&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can split &lt;code&gt;addConnection()&lt;/code&gt; into two methods: validation and linking.&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;ExampleComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;//...&lt;/span&gt;
      &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;usersChange&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;EventEmitter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&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;protected&lt;/span&gt; &lt;span class="nf"&gt;addConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toItem&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isItemConnectable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toItem&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;displayError&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;errEmptyItemMsg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="k"&gt;return&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hasNewConnection&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;addItemToUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toItem&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;users&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;hasNewConnection&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;connected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toItem&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;usersChange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&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;// ...&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;function&lt;/span&gt; &lt;span class="nf"&gt;isItemConnectable&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="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// here we have 100 lines of validation...&lt;/span&gt;
      &lt;span class="c1"&gt;// ...&lt;/span&gt;
      &lt;span class="c1"&gt;// ... very complex logic here ...&lt;/span&gt;
      &lt;span class="c1"&gt;// ...&lt;/span&gt;
      &lt;span class="c1"&gt;// ... not like this :)&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&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;data&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;function&lt;/span&gt; &lt;span class="nf"&gt;addItemToUsers&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="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;hasNewConnection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;hasNewConnection&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updatedUsers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
      &lt;span class="k"&gt;for &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;user&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;users&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;itemRefs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&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;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;updatedUsers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;itemRefs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;itemRefs&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;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
          &lt;span class="nx"&gt;hasNewConnection&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;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;updatedUsers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&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;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;updatedUsers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;hasNewConnection&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;Because the new functions should be pure, they cannot modify their arguments. So, in &lt;code&gt;addItemToUsers()&lt;/code&gt;, we had to create a new array of users and make a shallow copy for the users we want to connect, instead of mutating them directly.&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;// before&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="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;itemRefs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;itemRefs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// after&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="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;itemRefs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&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;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;updatedUsers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;itemRefs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;itemRefs&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;id&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;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;updatedUsers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&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;usersChange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, we actually fixed quite a nasty bug of data de-synchronization, described in more detail in &lt;a href="https://dev.to/oz/angular-inputs-and-single-source-of-truth-4kog"&gt;this article&lt;/a&gt;. Now we will emit a new array of users every time a new connection is created, so the parent component will have the correct data. Bingo!&lt;/p&gt;

&lt;p&gt;Now we can reuse our super complex logic in other places — the new functions have no dependencies, all they need are their arguments.&lt;/p&gt;

&lt;p&gt;When refactoring your code into pure functions, require as little information in arguments as possible. If your function requires &lt;code&gt;product: HugeProductDataStructure&lt;/code&gt; and in its code it uses &lt;code&gt;product&lt;/code&gt; just for &lt;code&gt;product.id&lt;/code&gt; and &lt;code&gt;product.price&lt;/code&gt;, then it is much better to define arguments like &lt;code&gt;productId&lt;/code&gt; and &lt;code&gt;productPrice&lt;/code&gt;, rather than requiring a structure that might be difficult to fetch in some places of your code. But don’t over-explode your list of arguments ;)&lt;/p&gt;

&lt;h3&gt;
  
  
  Component State Management
&lt;/h3&gt;

&lt;p&gt;Some methods just can not avoid using this because they have to modify the state of your component. You can still make such code reusable, by moving this logic into a separate file, called “local store”.&lt;/p&gt;

&lt;p&gt;A local store might be represented as a class or as a function (see examples in &lt;a href="https://ngrx.io/guide/signals/signal-store"&gt;NgRx SignalStore docs&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Here is an example of how we could move logic, responsible for saving users, to a local store:&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleStore&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;api&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;ApiService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;saveUsers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sideEffect&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&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;_&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;_&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;exhaustMap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;users&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;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;saveUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&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;err&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;displayError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;msg&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="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-example&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// ...&lt;/span&gt;
      &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ExampleStore&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;ExampleComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&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;ExampleStore&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nf"&gt;saveUsers&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;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;saveUsers&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;users&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;Because of this refactoring, we now can reuse logic, responsible for saving users' data (which often is not as primitive as this example) in other places of our code, simply by injecting the ExampleStore.&lt;/p&gt;

&lt;p&gt;You can read more about the benefits that this refactoring brings, and about different kinds of stores, in &lt;a href="https://dev.to/oz/application-state-management-with-angular-signals-1371"&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the previous code example, you might notice that &lt;code&gt;saveUsers()&lt;/code&gt; has just one line, and some of you may ask, “Maybe we could just call this method directly from the template? Why the extra wrapping?”&lt;/p&gt;

&lt;p&gt;The answer here is: it is up to you to decide. Some developers trust their local stores and IDEs, so if the store’s method name or signature changes, the IDE will automatically update it in the template. Other developers say that templates calling only component’s methods look cleaner and more reliable to them. This topic is very subjective, and there cannot be only one correct answer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Miscellaneous
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Prefer &lt;a href="https://en.wikipedia.org/wiki/Composition_over_inheritance"&gt;composition to inheritance&lt;/a&gt;. Never extend components (yes, never). In some very rare cases, when you see that only inheritance can be used, it is okay to extend stores. However, never extend components. We might think that we increase code reusability this way, but there are other ways to achieve the same result without inheritance. What we sacrifice when we extend components is &lt;strong&gt;maintainability&lt;/strong&gt;, and that is a very important aspect of the code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Even if &lt;code&gt;::ng-deep&lt;/code&gt; is un-deprecated, try to avoid it. When it’s not possible (and there are such cases), use it with extreme care. To help your future self, use very specific selectors inside &lt;code&gt;::ng-deep&lt;/code&gt;. When you reuse components that use &lt;code&gt;::ng-deep&lt;/code&gt;, and these components have multiple levels of sub-components, things might quickly go out of control if the selectors inside &lt;code&gt;::ng-deep&lt;/code&gt; are not specific enough.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When using Observables, avoid nested subscriptions. Additionally, methods of your services that return observables are much more reusable than methods that subscribe. You don’t always need that level of reusability, but sometimes you might want to reuse code that is inside a method that subscribes and unsubscribes. In such cases, just refactor that method into two: one that returns an observable, and the second one that uses that observable.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;🪽 Do you like this article? Share it and let it fly! 🛸&lt;/p&gt;

&lt;p&gt;💙 &lt;em&gt;If you enjoy my articles, consider &lt;a href="https://twitter.com/eugeniyoz"&gt;following me on Twitter&lt;/a&gt;, and/or &lt;a href="https://medium.com/@eugeniyoz"&gt;subscribing&lt;/a&gt; to receive my new articles by email.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Angular Inputs and Single Source of Truth</title>
      <dc:creator>Evgeniy OZ</dc:creator>
      <pubDate>Sun, 05 May 2024 12:41:54 +0000</pubDate>
      <link>https://forem.com/oz/angular-inputs-and-single-source-of-truth-4kog</link>
      <guid>https://forem.com/oz/angular-inputs-and-single-source-of-truth-4kog</guid>
      <description>&lt;p&gt;The main way for Angular components to receive external data is through “inputs.” In this article, I’ll explain why the &lt;strong&gt;Single Source of Truth&lt;/strong&gt; principle should be applied to inputs.&lt;/p&gt;

&lt;p&gt;Wikipedia provides a scientific description of the &lt;a href="https://en.wikipedia.org/wiki/Single_source_of_truth"&gt;Single Source of Truth&lt;/a&gt;, but if we apply it to Angular components and their inputs, it will sound like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Inputs of a component should only be modified from outside the component.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This simple rule can save your code from very weird bugs. Let’s explore the simplest case:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/stackblitz-starters-zyojns?ctl=1&amp;amp;embed=1&amp;amp;file=src%2Fmain.ts&amp;amp;hideExplorer=1&amp;amp;view=preview" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this small demo (&lt;a href="https://stackblitz.com/edit/stackblitz-starters-zyojns?file=src%2Fmain.ts"&gt;source code&lt;/a&gt;), you can add items to your shopping cart, but after 10 seconds, the list will be replaced with some items you didn’t pick.&lt;/p&gt;

&lt;p&gt;This demo emulates a situation where the shopping cart data is loaded from the server, but while the request was loading, the user was able to add some items to the cart. Maybe it’s not the best demo, but I hope it illustrates the idea. Creating code with bugs intentionally is not as easy as it happens unintentionally 😉&lt;/p&gt;

&lt;p&gt;Generally speaking, the state of our component is globally mutable. We should avoid it everywhere, not only in components. But let’s see how we can avoid it in components.&lt;/p&gt;

&lt;h3&gt;
  
  
  Immutable Inputs
&lt;/h3&gt;

&lt;p&gt;Thankfully, Angular gives us two ways to create inputs, that can not be modified inside the component: accessors and signals.&lt;/p&gt;

&lt;p&gt;In Angular before v17 accessors were the only way:&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ShoppingCart&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="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;=&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="kd"&gt;set&lt;/span&gt; &lt;span class="nf"&gt;items&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="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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;items&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;_items&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;In Angular v17.1 we got Signal Inputs:&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ShoppingCart&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="nx"&gt;input&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fewer lines, more awesomeness.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;There are also more practical reasons to use signal inputs over setters, you can read about them in &lt;a href="https://riegler.fr/blog/2024-05-01-input-setters-caveats"&gt;this article&lt;/a&gt; by &lt;a href="https://twitter.com/Jean__Meche"&gt;Matthieu Riegler&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now if we try to update items inside the component:&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ShoppingCart&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="nx"&gt;input&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="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;api&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;Api&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nf"&gt;constructor&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;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCartItems&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;items&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="nx"&gt;items&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;items&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="c1"&gt;//         ^^:&lt;/span&gt;
          &lt;span class="c1"&gt;// 🔴 Property 'set' does not exist on type 'InputSignal&amp;lt;Item[]&amp;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;TypeScript generates an error and protects our code.&lt;/p&gt;

&lt;p&gt;If you encounter an error like this, do not try to find a workaround — Angular and TypeScript are on your side here and trying to help you. Modify your code to fix the bug. Sometimes it will require effort and time, but you’ll fix one of the nastiest kinds of bugs.&lt;/p&gt;

&lt;p&gt;To fix our example, we should decide which part of our code should be the source of truth for the list of items in our shopping cart. Only that code will be allowed to modify (mutate) the list of items. Also, this code should be responsible for protecting the list from undesired modifications.&lt;/p&gt;

&lt;p&gt;In our example, the root component doesn’t need to know what items are in the shopping cart, so it should either the Api service (which is shared globally), or the ShoppingCart component.&lt;/p&gt;

&lt;p&gt;In real apps, we might need information about the shopping cart items not only in the &lt;code&gt;ShoppingCart&lt;/code&gt;, but also in the navigation components.&lt;/p&gt;

&lt;p&gt;So, let’s make the Api service the source of truth for this list:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/stackblitz-starters-k9phju?ctl=1&amp;amp;embed=1&amp;amp;file=src%2Fmain.ts&amp;amp;hideExplorer=1&amp;amp;view=preview" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Now, if you explore the &lt;a href="https://stackblitz.com/edit/stackblitz-starters-k9phju?file=src%2Fapi.ts"&gt;source code&lt;/a&gt;, you’ll find that most of the logic is moved to the Api service, and this service now has the only source of truth for the shopping cart items. And now, this service protects this source of truth from unintentional modifications.&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;addItemToCart&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;untracked&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;$isLoading&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="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;_$cartItems&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;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Array&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If you are curious why &lt;code&gt;untracked()&lt;/code&gt; is used here, &lt;a href="https://dev.to/oz/angular-signals-reactive-context-and-dynamic-dependency-tracking-5e6l"&gt;this article&lt;/a&gt; will be interesting for you.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The code of our components becomes much more compact, and the &lt;code&gt;ShoppingCart&lt;/code&gt; component is now a “dumb” component.&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;ShoppingCart&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="nx"&gt;input&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;removeItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;output&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="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nf"&gt;remove&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;removeItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&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;The Api service has a little more code now, but for a very good reason — we’ve fixed a bug!&lt;/p&gt;

&lt;p&gt;This article uses new features of Angular v17.1, but you could achieve it with just accessors and observables in any version of Angular. Code examples are far from perfect, and it was done intentionally to illustrate how a bug can be introduced and fixed.&lt;/p&gt;

&lt;p&gt;The “Signal Source of Truth” architecture (or “rule,” or “principle”) states that if some information is shared across the application, there should be only one part of the code that can mutate this information. This principle can protect your application from bugs, which, as is often the case in practice, are much worse than theoretical examples in articles. Apply it to your components and services to make them more robust!&lt;/p&gt;

&lt;p&gt;🪽 Do you like this article? Share it and let it fly! 🛸&lt;/p&gt;

&lt;p&gt;💙 &lt;em&gt;If you enjoy my articles, consider &lt;a href="https://twitter.com/eugeniyoz"&gt;following me on Twitter&lt;/a&gt;, and/or &lt;a href="https://medium.com/@eugeniyoz"&gt;subscribing&lt;/a&gt; to receive my new articles by email.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>angular</category>
      <category>signals</category>
      <category>ssot</category>
    </item>
    <item>
      <title>Angular Signals, Reactive Context, and Dynamic Dependency Tracking</title>
      <dc:creator>Evgeniy OZ</dc:creator>
      <pubDate>Wed, 24 Apr 2024 09:24:42 +0000</pubDate>
      <link>https://forem.com/oz/angular-signals-reactive-context-and-dynamic-dependency-tracking-5e6l</link>
      <guid>https://forem.com/oz/angular-signals-reactive-context-and-dynamic-dependency-tracking-5e6l</guid>
      <description>&lt;p&gt;To effectively use Angular Signals, it’s crucial to understand the concept of the “reactive context” and how dependency tracking works. In this article, I’ll explain both these things, and show how to avoid some related bugs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dependency Tracking
&lt;/h3&gt;

&lt;p&gt;When you use Angular Signals, you don’t need to worry about subscribing and unsubscribing. To understand how it works, we’ll need a few terms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dependency Graph&lt;/strong&gt;: graph of nodes, every node implements ReactiveNode interface;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Producers&lt;/strong&gt;: nodes that contain values and notify about new values (they “produce reactivity”);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consumers&lt;/strong&gt;: nodes that read produced values (they “consume reactivity”);&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Signals are &lt;em&gt;producers&lt;/em&gt;, &lt;code&gt;computed()&lt;/code&gt; is &lt;em&gt;producer&lt;/em&gt; and &lt;em&gt;consumer&lt;/em&gt; simultaneously, &lt;code&gt;effect()&lt;/code&gt; is &lt;em&gt;consumer&lt;/em&gt;, templates are &lt;em&gt;consumers&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can read a more detailed article about the &lt;a href="https://medium.com/@eugeniyoz/dependency-graph-in-angular-signals-53ee47f75e21"&gt;Dependency Graph in Angular Signals&lt;/a&gt; (with animated graph example).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;How automatic dependency tracking works&lt;/strong&gt;: there is a variable, global for all the reactive nodes, &lt;code&gt;activeConsumer&lt;/code&gt;, and every time &lt;code&gt;computed()&lt;/code&gt; runs its computation function, every time &lt;code&gt;effect()&lt;/code&gt; runs its side-effects function, or a template is being checked for changes, they:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read the value of &lt;code&gt;activeConsumer&lt;/code&gt; (to remember the previous consumer);&lt;/li&gt;
&lt;li&gt;Register themselves as an &lt;code&gt;activeConsumer&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Run the function or execute a template (some signals might be read during this step);&lt;/li&gt;
&lt;li&gt;Register the previous consumer (from Step 1) as an &lt;code&gt;activeConsumer&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When any producer is read, it retrieves the value of &lt;code&gt;activeConsumer&lt;/code&gt; and includes this active consumer in the list of consumers dependent on the signal. When a signal is updated, it subsequently sends a notification to every consumer from its list.&lt;/p&gt;

&lt;p&gt;Let’s examine what happens step by step in this 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="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;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
       Items count: {{ $items().length }}
       Active items count: {{ $activeItemsCount() }}
    `&lt;/span&gt;   
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleComponent&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;$items&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;id&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;$isActive&lt;/span&gt;&lt;span class="p"&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;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;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;$activeItemsCount&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;return&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;getActiveItems&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;length&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;getActiveItems&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="nf"&gt;$items&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;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$isActive&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;ol&gt;
&lt;li&gt;The template reads the value of &lt;code&gt;activeConsumer&lt;/code&gt; and saves it to the &lt;code&gt;prevConsumer&lt;/code&gt; variable (this variable is local for the template);&lt;/li&gt;
&lt;li&gt;The template sets itself as &lt;code&gt;activeConsumer&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;It calls &lt;code&gt;$items()&lt;/code&gt; signal to get a value;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$items&lt;/code&gt; signal retrieves the value of &lt;code&gt;activeConsumer&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;The received value is not empty (it contains a link to the template), so &lt;code&gt;$items&lt;/code&gt; signal puts this value (link to our template) into the list of consumers. After that, every time $items is updated, the template will be notified — a new link has been created in the dependency graph;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$items&lt;/code&gt; returns a value to the template;&lt;/li&gt;
&lt;li&gt;The template reads the value of &lt;code&gt;$activeItemsCount&lt;/code&gt; signal. To return a value, &lt;code&gt;$activeItemsCount&lt;/code&gt; needs to run its computation function - the function we pass in our code to &lt;code&gt;computed()&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Before running the computation function, &lt;code&gt;$activeItemsCount&lt;/code&gt; reads the value of &lt;code&gt;activeConsumer&lt;/code&gt; and saves it to its local variable prevConsumer. Because &lt;code&gt;$activeItemsCount&lt;/code&gt; is also a consumer, it puts a link to itself to the &lt;code&gt;activeConsumer&lt;/code&gt; variable;&lt;/li&gt;
&lt;li&gt;Computation function calls &lt;code&gt;getActiveItems()&lt;/code&gt; function;&lt;/li&gt;
&lt;li&gt;Inside this function, we read the value of &lt;code&gt;$items&lt;/code&gt; — steps from 3 to 6 are repeated, but because our template is already dependent on &lt;code&gt;$items&lt;/code&gt;, Step 5 will not add a new consumer to the list;&lt;/li&gt;
&lt;li&gt;When the value (an array of items) is returned, &lt;code&gt;getActiveItems()&lt;/code&gt; reads every element of this array and reads the value of &lt;code&gt;$isActive()&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$isActive&lt;/code&gt; is a signal. So, before it returns a value, it repeats steps 3–6. During step 4, &lt;code&gt;$isActive&lt;/code&gt; retrieves the value of &lt;code&gt;activeConsumer&lt;/code&gt;. At this moment &lt;code&gt;activeConsumer&lt;/code&gt; contains a link to &lt;code&gt;$activeItemsCount&lt;/code&gt;, so at step 5 &lt;code&gt;$isActive&lt;/code&gt; (each one from the array) will add &lt;code&gt;$activeItemsCount&lt;/code&gt; to the list of dependent consumers. Any time &lt;code&gt;$isActive&lt;/code&gt; is updated, &lt;code&gt;$activeItemsCount&lt;/code&gt; will be notified, &lt;code&gt;$activeItemsCount&lt;/code&gt; will notify our template that its value is stale and needs to be recomputed. After that, our template &lt;strong&gt;&lt;em&gt;eventually&lt;/em&gt;&lt;/strong&gt; (not right after the notification) will ask &lt;code&gt;$activeItemsCount&lt;/code&gt; what is the new value, and steps from 7 to 14 will be repeated;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;getActiveItems()&lt;/code&gt; returns a value. &lt;code&gt;$activeItemsCount&lt;/code&gt; uses this value for computation and before returning it, it puts the value of its local variable &lt;code&gt;prevConsumer&lt;/code&gt; to the &lt;code&gt;activeConsumer&lt;/code&gt; variable;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$activeItemsCount&lt;/code&gt; returns a value;&lt;/li&gt;
&lt;li&gt;The template puts the previously saved value of &lt;code&gt;prevConsumer&lt;/code&gt; to &lt;code&gt;activeConsumer&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It is not a short list, but please read it thoroughly.&lt;/p&gt;

&lt;p&gt;The most important thing here is: that consumers (&lt;code&gt;computed()&lt;/code&gt;, &lt;code&gt;effect()&lt;/code&gt;, &lt;code&gt;templates&lt;/code&gt;) don’t need to worry about adding signals they read to the list of dependencies. Signals will do it themselves, using the &lt;code&gt;activeConsumer&lt;/code&gt; variable. This variable is accessible to any reactive node, so it doesn’t matter how deep in the functions chain some signal will be read — any signal will get the value of &lt;code&gt;activeConsumer&lt;/code&gt; and add it to the list of consumers.&lt;/p&gt;

&lt;p&gt;Remember: if you call a function in a template, &lt;code&gt;computed()&lt;/code&gt; or &lt;code&gt;effect()&lt;/code&gt; (a consumer), and that function reads another function and that function reads another function…, and finally, at some level, a function reads a signal, and that signal adds that consumer to its list and will notify it about the updates.&lt;/p&gt;

&lt;p&gt;Debugging-like reading can be tedious, so let me entertain you with this &lt;a href="https://stackblitz.com/edit/stackblitz-starters-zvhx3t?file=src%2Fmain.ts"&gt;small app&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/stackblitz-starters-zvhx3t?ctl=1&amp;amp;embed=1&amp;amp;file=src%2Fmain.ts&amp;amp;hideExplorer=1&amp;amp;view=preview" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Please do the following in that app:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click button “2” to make it active, then click it again. Notice that the “Active items” text above the buttons reflects the change;&lt;/li&gt;
&lt;li&gt;Click the “Add Item” button;&lt;/li&gt;
&lt;li&gt;Click button “4”. Notice that “Active items” doesn’t reflect the change;&lt;/li&gt;
&lt;li&gt;Click button “2”;&lt;/li&gt;
&lt;li&gt;Now click button “4” a few times and notice that the “Active items” text reflects it as expected.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But why? Let’s check the code:&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;type&lt;/span&gt; &lt;span class="nx"&gt;Item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;id&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;$isActive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WritableSignal&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;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;my-app&lt;/span&gt;&lt;span class="dl"&gt;'&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&amp;gt;Active items: {{ $activeItems() }}&amp;lt;/div&amp;gt;
        &amp;lt;div&amp;gt;
          &amp;lt;span&amp;gt;Click to to toggle:&amp;lt;/span&amp;gt;
          @for(item of items; track item.id) {
            &amp;lt;button (click)="item.$isActive.set(!item.$isActive())" 
                    [class.active]="item.$isActive()"&amp;gt;
              {{ item.id }}
           &amp;lt;/button&amp;gt;
          }
        &amp;lt;/div&amp;gt;
        &amp;lt;div&amp;gt;
          &amp;lt;button (click)="addItem()"&amp;gt;Add Item&amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;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;App&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;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="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;id&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;$isActive&lt;/span&gt;&lt;span class="p"&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;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;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;$isActive&lt;/span&gt;&lt;span class="p"&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="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&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="na"&gt;$isActive&lt;/span&gt;&lt;span class="p"&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;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;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;$activeItems&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
        &lt;span class="k"&gt;for &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;item&lt;/span&gt; &lt;span class="k"&gt;of&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="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;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$isActive&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&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;id&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;return&lt;/span&gt; &lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, &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="k"&gt;protected&lt;/span&gt; &lt;span class="nf"&gt;addItem&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;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;id&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;length&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="na"&gt;$isActive&lt;/span&gt;&lt;span class="p"&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="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;Now let’s analyze why the “Active items” line is not updated correctly.&lt;/p&gt;

&lt;p&gt;Binding in our template:&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&amp;gt;&lt;/span&gt;Active items: {{ $activeItems() }}&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;&lt;code&gt;$activeItems&lt;/code&gt; is a signal, provided by &lt;code&gt;computed()&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;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;$activeItems&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
      &lt;span class="k"&gt;for &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;item&lt;/span&gt; &lt;span class="k"&gt;of&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="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;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$isActive&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&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;id&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;return&lt;/span&gt; &lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, &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;p&gt;The function we pass to &lt;code&gt;computed()&lt;/code&gt; will be re-executed every time any of the signals it reads is updated. What signals do we read there?&lt;/p&gt;

&lt;p&gt;It’s &lt;code&gt;$isActive&lt;/code&gt; signal of every item in the &lt;code&gt;this.items&lt;/code&gt; array.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Notice how the &lt;code&gt;$&lt;/code&gt; sign in the name of the variable helps quickly find the sources of reactivity. This principle applies similarly to the &lt;code&gt;effect()&lt;/code&gt; function and component templates. That’s why I use it, but it’s simply a matter of personal preference.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So why &lt;code&gt;$activeItems&lt;/code&gt; was not updated after steps 2 and 3?&lt;/p&gt;

&lt;p&gt;The computation function will only be re-executed when one of the signals it depends on is updated.&lt;/p&gt;

&lt;p&gt;When we click “Add Item”, we modify &lt;code&gt;this.items&lt;/code&gt; and create a new signal inside the new item. But before this moment, our &lt;code&gt;computed()&lt;/code&gt; function had never read that signal, so it does not have it in the list of dependencies.&lt;/p&gt;

&lt;p&gt;Before and &lt;strong&gt;after&lt;/strong&gt; clicking “Add Item,” the list of signals that &lt;code&gt;$activeItems&lt;/code&gt; depends on remains unchanged: three &lt;code&gt;$isActive&lt;/code&gt; signals from the three items in &lt;code&gt;this.items&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Because none of these signals is modified when we click “Add Item”, &lt;code&gt;computed()&lt;/code&gt; will not be notified and the computation function will not be re-executed.&lt;/p&gt;

&lt;p&gt;We can toggle our new item in the list of buttons as many times as we want, but only the signals of the 3 first items will notify $activeItems and it will re-execute the function we sent.&lt;/p&gt;

&lt;p&gt;But if we re-execute our computation function, it will read all the items from &lt;code&gt;this.items&lt;/code&gt; again and will read the new signal, finally. The new signal will become the new dependency of the $activeItems node, and it will be notified every time one of them is changed.&lt;/p&gt;

&lt;p&gt;To do this, we need to modify one of the existing dependencies: that’s why we click button “2” in step 4.&lt;/p&gt;

&lt;p&gt;This example is created to remind you, that functions we pass to &lt;code&gt;computed()&lt;/code&gt; and &lt;code&gt;effect()&lt;/code&gt; will only be re-executed, when one of the producers they read is updated.&lt;/p&gt;

&lt;p&gt;This is why it is always useful to double-check, what dependencies your &lt;code&gt;computed()&lt;/code&gt; has and what of them should cause a re-computation. If some of them should not — use &lt;code&gt;untracked()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Some of the functions we pass to &lt;code&gt;computed()&lt;/code&gt; or &lt;code&gt;effect()&lt;/code&gt; might read signals (or functions they call might read signals).&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$petWalkingIsAllowed&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;return&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;$isFreeTime&lt;/span&gt;&lt;span class="p"&gt;()&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="nf"&gt;isItGoodWeatherOutside&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nf"&gt;isItGoodWeatherOutside&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="nf"&gt;$isSunny&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;$isWarm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;$isStormy&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;To understand if we should wrap such calls with &lt;code&gt;untracked()&lt;/code&gt; to avoid non-desired recomputations, we can use this logic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If we &lt;strong&gt;don’t want&lt;/strong&gt; our &lt;code&gt;computed()&lt;/code&gt; to compute a new result when that function (&lt;code&gt;isItGoodWeatherOutside()&lt;/code&gt;) returns a new value, then wrap it with &lt;code&gt;untracked()&lt;/code&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;$petWalkingIsAllowed&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;return&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;$isFreeTime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;untracked&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;$isItGoodWeatherOutside&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nf"&gt;isItGoodWeatherOutside&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="nf"&gt;$isSunny&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;$isWarm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;$isStormy&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;ul&gt;
&lt;li&gt;If on every new value from that function we &lt;strong&gt;do want&lt;/strong&gt; to re-run our computation, do not wrap it with &lt;code&gt;untracked()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see, &lt;code&gt;untracked()&lt;/code&gt; helps us control which dependencies we want to track. It also helps to manage another important aspect:&lt;/p&gt;

&lt;h3&gt;
  
  
  Reactive Context
&lt;/h3&gt;

&lt;p&gt;Above, in “How automatic dependency tracking works,” I’ve mentioned the variable &lt;code&gt;activeConsumer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;activeConsumer&lt;/code&gt; is not null, signals we read will add that &lt;code&gt;activeConsumer&lt;/code&gt; to the list of consumers, to later notify members of this list about modifications of a signal. If a reactive node is read while &lt;code&gt;activeConsumer&lt;/code&gt; is empty, it will not create any new link in the reactive nodes dependency graph.&lt;/p&gt;

&lt;p&gt;In other words, while &lt;code&gt;activeConsumer&lt;/code&gt; is set, we are reading signals within the &lt;em&gt;Reactive Context&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In the majority of cases, the reactive context will be handled automatically, and only the intended links and dependencies will be created and removed.&lt;/p&gt;

&lt;p&gt;But sometimes we unintentionally &lt;em&gt;leak&lt;/em&gt; the reactive context.&lt;/p&gt;

&lt;p&gt;Let’s try out this &lt;a href="https://stackblitz.com/edit/stackblitz-starters-hgrfbo?file=src%2Fmain.ts"&gt;app&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/stackblitz-starters-hgrfbo?ctl=1&amp;amp;embed=1&amp;amp;file=src%2Fmain.ts&amp;amp;hideExplorer=1&amp;amp;theme=dark&amp;amp;view=preview" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;If you try to use it, you’ll notice that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;clicking “Add Item” leads to a complete reset of all statuses;&lt;/li&gt;
&lt;li&gt;clicking to toggle the status changes it randomly, affecting more than just one button.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Can you quickly spot the bug?&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="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
        &amp;lt;div&amp;gt;Active items: {{ $activeItems() }}&amp;lt;/div&amp;gt;
        &amp;lt;div class="flex-row"&amp;gt;
          &amp;lt;span&amp;gt;Click to to toggle:&amp;lt;/span&amp;gt;
          @for(item of $items(); track item.id) {
          &amp;lt;button (click)="item.$isActive.set(!item.$isActive())" [class.active]="item.$isActive()" [style.transform]="'scale('+item.$scale()+')'"&amp;gt;
            {{ item.id }}
          &amp;lt;/button&amp;gt;
          }
        &amp;lt;/div&amp;gt;
        &amp;lt;div&amp;gt;
          &amp;lt;button (click)="addItem()"&amp;gt;Add Item&amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;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;App&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;$itemsCount&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;3&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;$items&lt;/span&gt;&lt;span class="p"&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="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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Generating items!&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="na"&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="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
        &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;id&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="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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;$itemsCount&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="nx"&gt;id&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;$isActive&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="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;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.5&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;$scale&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="nf"&gt;$isActive&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mf"&gt;1.2&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="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;$isActive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;$scale&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="nx"&gt;items&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;$activeItems&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
        &lt;span class="k"&gt;for &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;item&lt;/span&gt; &lt;span class="k"&gt;of&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="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;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$isActive&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&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;id&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;return&lt;/span&gt; &lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, &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="k"&gt;protected&lt;/span&gt; &lt;span class="nf"&gt;addItem&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;$itemsCount&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;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&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="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;What can we see here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We render the list of items from $items, which is &lt;code&gt;computed()&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$items&lt;/code&gt; generates a new array of items, and their count is controlled by the &lt;code&gt;$itemsCount&lt;/code&gt; signal. Every time we modify $itemsCount, items are regenerated;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;addItem()&lt;/code&gt; simply increments &lt;code&gt;$itemsCount&lt;/code&gt;, triggering recomputation of &lt;code&gt;$items&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we can see why “Add Item” works this way. Let’s try to figure out why the status toggling behaves strangely.&lt;/p&gt;

&lt;p&gt;If we open the console, we’ll notice that every time we click a button, a “Generating items!” warning is logged. But why? We’re not modifying $itemsCount, so why is &lt;code&gt;$items&lt;/code&gt; recomputed?&lt;/p&gt;

&lt;p&gt;Perhaps you’ve already noticed that the computation function of &lt;code&gt;$items&lt;/code&gt; reads one more source of reactivity: the signal &lt;code&gt;$isActive&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;$scale&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="nf"&gt;$isActive&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mf"&gt;1.2&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This signal (&lt;code&gt;$isActive&lt;/code&gt;) is being read in the reactive context: &lt;code&gt;activeConsumer&lt;/code&gt; contains &lt;code&gt;$items&lt;/code&gt;, so &lt;code&gt;$isActive&lt;/code&gt; will notify &lt;code&gt;$items&lt;/code&gt; about every change. Therefore, when we modify &lt;code&gt;$isActive&lt;/code&gt; in an attempt to toggle this status, we trigger recomputation of &lt;code&gt;$items&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There are multiple ways to fix this bug, but this approach prevents the leakage of the reactive context:&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;$scale&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="nf"&gt;untracked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$isActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mf"&gt;1.2&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What does &lt;code&gt;untracked()&lt;/code&gt; &lt;a href="https://github.com/angular/angular/blob/75a186e321cb417685b2f13e9961906fc0aed36c/packages/core/src/render3/reactivity/untracked.ts#L15"&gt;do&lt;/a&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="cm"&gt;/** 
     * https://github.com/angular/angular/blob/75a186e321cb417685b2f13e9961906fc0aed36c/packages/core/src/render3/reactivity/untracked.ts#L15
     *
     * packages/core/src/render3/reactivity/untracked.ts
     *
     **/&lt;/span&gt;
    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;untracked&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;nonReactiveReadsFn&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="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;T&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;prevConsumer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setActiveConsumer&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;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;nonReactiveReadsFn&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setActiveConsumer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevConsumer&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;ul&gt;
&lt;li&gt;sets &lt;code&gt;activeConsumer&lt;/code&gt; to null and saves the returned value to the local variable &lt;code&gt;prevConsumer&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;runs the given function;&lt;/li&gt;
&lt;li&gt;restores &lt;code&gt;activeConsumer&lt;/code&gt; from &lt;code&gt;prevConsumer&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It temporarily disables the reactive context, executes our function, and then restores the reactive context.&lt;/p&gt;

&lt;p&gt;Because of that, while our function is being executed, if any signals are being read, they will read null from &lt;code&gt;activeConsumer&lt;/code&gt; and won’t add it to their lists of consumers. In other words, no new dependencies will be created.&lt;/p&gt;

&lt;p&gt;In this example, we have some “hints” in the console, and our code is very small and simple. In real apps, signal reading might be buried deep within the function call chain, and the code could be much larger and more complex. Bugs like this can be challenging to debug in real apps, which is why I recommend preventing them by using &lt;code&gt;untracked()&lt;/code&gt; whenever you don't want to leak the reactive context.&lt;/p&gt;

&lt;p&gt;There are quite interesting and &lt;a href="https://github.com/angular/angular/pull/54614#issue-2155451129"&gt;unexpected&lt;/a&gt; ways to leak the reactive context:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating an instance of a class that reads some signals;&lt;/li&gt;
&lt;li&gt;Calling a function that calls another function, which reads a signal;&lt;/li&gt;
&lt;li&gt;Emitting a new value to an observable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you use &lt;code&gt;computed()&lt;/code&gt; and &lt;code&gt;effect()&lt;/code&gt;,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read other signals with caution — they’ll rerun the entire function every time they change, triggered by any other function.&lt;/li&gt;
&lt;li&gt;Make these functions easy to read and understand;&lt;/li&gt;
&lt;li&gt;Double-check every source of reactivity that your function consumes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As is often the case, implicit dependency tracking brings not only benefits but also some trade-offs. But when used with skill and caution, you can build wonderful apps with Angular Signals!&lt;/p&gt;

&lt;p&gt;I extend my heartfelt gratitude to the reviewers whose insightful comments and constructive feedback greatly contributed to the refinement of this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://twitter.com/rainerhahnekamp"&gt;Rainer Hahnekamp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/joshuamorony"&gt;Joshua Morony&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;🪽 Do you like this article? Share it and let it fly! 🛸&lt;/p&gt;

&lt;p&gt;💙 &lt;em&gt;If you enjoy my articles, consider &lt;a href="https://twitter.com/eugeniyoz"&gt;following me on Twitter&lt;/a&gt;, and/or &lt;a href="https://medium.com/@eugeniyoz"&gt;subscribing&lt;/a&gt; to receive my new articles by email.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Angular Signals: Best Practices</title>
      <dc:creator>Evgeniy OZ</dc:creator>
      <pubDate>Mon, 01 Apr 2024 10:20:40 +0000</pubDate>
      <link>https://forem.com/oz/angular-signals-best-practices-4gfd</link>
      <guid>https://forem.com/oz/angular-signals-best-practices-4gfd</guid>
      <description>&lt;p&gt;In this article, I share my experience of working with Angular Signals after almost a year of using them.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to use Signals?
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;In templates;&lt;/li&gt;
&lt;li&gt;When you need to react to changes in a value without a time aspect.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In Angular templates, Signals are better than Observables: they schedule Change Detection without any pipes, they are glitch-free, and you can read the same signal multiple times and it will be “free” in terms of performance (and read values are guaranteed to be the same). There are other reasons that are not so easy to explain briefly, but that’s already enough to make a rule: every variable (that might change) in your &lt;strong&gt;new&lt;/strong&gt; templates should be a Signal.&lt;/p&gt;

&lt;p&gt;Outside of templates, Signals also can be used for reactivity, but, as I mentioned, without a time aspect.&lt;/p&gt;

&lt;p&gt;I once wrote a post on Twitter about it, and now I’ll post it here, updated and improved:&lt;/p&gt;

&lt;p&gt;There are two ways to create reactive variables in Angular: Observables and Signals. If you describe in words, how your variable should express its reactivity, you’ll see what you need to use.&lt;/p&gt;

&lt;p&gt;If the role of a variable can be described as conditions, then you need a Signal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“if this variable has this value, then display this list”&lt;/li&gt;
&lt;li&gt;“if this variable has this value, this button is disabled”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the description of a variable’s role includes words, related to time, you need an Observable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“&lt;strong&gt;when&lt;/strong&gt; the cursor moves…”&lt;/li&gt;
&lt;li&gt;“&lt;strong&gt;wait&lt;/strong&gt; for the file uploading event and then…”&lt;/li&gt;
&lt;li&gt;“every &lt;strong&gt;time&lt;/strong&gt; this event happens, do this…”&lt;/li&gt;
&lt;li&gt;“&lt;strong&gt;until&lt;/strong&gt; this event…”&lt;/li&gt;
&lt;li&gt;“for N &lt;strong&gt;seconds&lt;/strong&gt; ignore…”&lt;/li&gt;
&lt;li&gt;“&lt;strong&gt;after&lt;/strong&gt; this request…”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Signals have no time axis, and they can not delay a value — they always have a value, and their consumers should be always able to read it.&lt;/p&gt;

&lt;p&gt;Consumers of Signals, &lt;code&gt;computed()&lt;/code&gt;, &lt;code&gt;effect()&lt;/code&gt;, and templates do not guarantee that they will read every new value written to the Signals they watch. An updated Signal will be &lt;em&gt;eventually&lt;/em&gt; read, not instantly after the update as it happens with Observables. Consumers decide when they will read the new value using their scheduling mechanisms. It might be “in the next task,” “during the next Change Detection cycle,” or at some other moment, up to the consumer.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to use &lt;code&gt;computed()&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Whenever you like!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;computed()&lt;/code&gt; is the best thing in Angular Signals, incredibly handy and safe to use. Using &lt;code&gt;computed()&lt;/code&gt;, you’ll make your code more declarative (you can read more about it in &lt;a href="https://medium.com/@eugeniyoz/creating-angular-components-template-first-declarative-approach-00c4a4791270"&gt;this article&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;There are just two rules about the usage of &lt;code&gt;computed()&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Do not modify things in &lt;code&gt;computed()&lt;/code&gt;. It should compute a new result, that’s it. Do not modify the DOM, do not mutate variables using &lt;code&gt;this&lt;/code&gt;, and do not call functions that might do that. Do not push values to Observables — it will cause unintentional reactive context propagation (explained below for &lt;code&gt;effect()&lt;/code&gt;). &lt;code&gt;computed()&lt;/code&gt; should not have side effects, it should be a &lt;a href="https://en.wikipedia.org/wiki/Pure_function"&gt;pure function&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Do not make asynchronous calls in &lt;code&gt;computed()&lt;/code&gt;. This function does not allow modification of Signals (and it is amazingly helpful), but it can not track asynchronous code. Moreover, Angular Signals are strictly synchronous, so if you want to use asynchronous code in &lt;code&gt;computed()&lt;/code&gt;, you are doing something wrong. So, no &lt;code&gt;setTimeout()&lt;/code&gt;, no Promises, no other asynchronous things.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  When to use &lt;code&gt;effect()&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Angular docs say that you’ll rarely need &lt;code&gt;effect()&lt;/code&gt; and &lt;a href="https://angular.dev/guide/signals#use-cases-for-effects"&gt;discourage&lt;/a&gt; you from using it (&lt;a href="https://gist.github.com/e-oz/99d04094abe5007d882f35879eb00da3"&gt;copy&lt;/a&gt;, if docs will be edited).&lt;/p&gt;

&lt;p&gt;And that info is correct: you rarely need &lt;code&gt;effect()&lt;/code&gt;… if your code is declarative ;)&lt;/p&gt;

&lt;p&gt;The more imperative your code, the more often you’ll need &lt;code&gt;effect()&lt;/code&gt;. There is no code without imperative parts, but we all should try to make our code as declarative as possible, so we do need to use &lt;code&gt;effect()&lt;/code&gt; as rarely as possible.&lt;/p&gt;

&lt;p&gt;Besides the dangers, mentioned by Angular docs (infinite loops, change detection errors), there is another thing, that might be quite nasty: effects are executed in a reactive context, and any code you call in effect, will be executed in a reactive context. If that code reads some signals, they will be added as dependencies to your effect. &lt;a href="https://github.com/angular/angular/pull/54614"&gt;Here&lt;/a&gt; Alex Rickabaugh explains the details.&lt;/p&gt;

&lt;p&gt;I still don’t want to encourage you to use &lt;code&gt;effect()&lt;/code&gt;, but I’ll give you advice on how to use it as safely as possible:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The function you provide to &lt;code&gt;effect()&lt;/code&gt; should be as small as possible. This way it will be easier to read and spot erroneous behavior.&lt;/li&gt;
&lt;li&gt;Read signals first, then wrap the rest of the effect into &lt;code&gt;untracked()&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="nf"&gt;effect&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;// reading the signals we need&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&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="nf"&gt;a&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;b&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="nf"&gt;b&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="nf"&gt;untracked&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;// rest of the code is here - this code should not&lt;/span&gt;
        &lt;span class="c1"&gt;// modify the signals we read above!&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;a&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Ok&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Mixing Signals and Observables
&lt;/h3&gt;

&lt;p&gt;…is ok!&lt;/p&gt;

&lt;p&gt;Your code will have Signals and Observables, at least because Signals can not be used for every kind of reactivity (see detailed explanation above). It is not an issue, it is perfectly fine.&lt;/p&gt;

&lt;p&gt;If you need some value from an Observable in your &lt;code&gt;computed()&lt;/code&gt;, create a Signal using &lt;code&gt;toSignal()&lt;/code&gt; (outside of &lt;code&gt;computed()&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;If you need to read a Signal in Observable’s &lt;code&gt;pipe()&lt;/code&gt;, there are two ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If you need to react to changes in that Signal in your Observable, then you need to convert that Signal into Observable and add it using some join operator.&lt;/li&gt;
&lt;li&gt;If you are sure you just need the current value of a Signal and you don’t need to react to its changes — you can read a Signal directly in your operators or &lt;code&gt;subscribe()&lt;/code&gt;. Observable is not a reactive context, so you don’t need &lt;code&gt;untracked()&lt;/code&gt; here.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;🪽 Do you like this article? Share it and let it fly! 🛸&lt;/p&gt;

&lt;p&gt;💙 &lt;em&gt;If you enjoy my articles, consider &lt;a href="https://twitter.com/eugeniyoz"&gt;following me on Twitter&lt;/a&gt;, and/or &lt;a href="https://medium.com/@eugeniyoz"&gt;subscribing&lt;/a&gt; to receive my new articles by email.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1770250842974695912-681" src="https://platform.twitter.com/embed/Tweet.html?id=1770250842974695912"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1770250842974695912-681');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1770250842974695912&amp;amp;theme=dark"
  }



&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webdev</category>
      <category>signals</category>
      <category>reactivity</category>
    </item>
    <item>
      <title>Preparing our Code for Zoneless Angular</title>
      <dc:creator>Evgeniy OZ</dc:creator>
      <pubDate>Sat, 16 Mar 2024 15:54:54 +0000</pubDate>
      <link>https://forem.com/oz/preparing-our-code-for-zoneless-angular-4d30</link>
      <guid>https://forem.com/oz/preparing-our-code-for-zoneless-angular-4d30</guid>
      <description>&lt;p&gt;This article explains how to modify your code to make your library or app work without Zone.js.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Zoneless Angular?
&lt;/h3&gt;

&lt;p&gt;In the article “&lt;a href="https://medium.com/@eugeniyoz/angular-change-detection-today-and-tomorrow-b9c64bd294f8"&gt;Angular Change Detection — Today and Tomorrow&lt;/a&gt;”, I’ve explained how different types of change detection work in Angular.&lt;/p&gt;

&lt;p&gt;The main benefit of making Angular apps zoneless is performance. No more unnecessary CD cycles and recomputations of values. No more checking every binding on every &lt;code&gt;mousemove&lt;/code&gt; event. No more &lt;code&gt;runOutsideAngular()&lt;/code&gt; calls to reduce the amount of CD cycles, no more juggling with &lt;code&gt;detach()&lt;/code&gt; and &lt;code&gt;detectChanges()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Another benefit: we can safely use &lt;code&gt;async..await&lt;/code&gt; syntax because we don’t rely anymore on monkey-patching Promises by Zone.js.&lt;/p&gt;

&lt;p&gt;Removing Zone.js dependency also removes the “Angular-compatible” term for JS tools: you don’t need to worry anymore if changes that some JS tool makes will be caught by Angular’s Change Detection and rendered correctly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Before your app goes zoneless, it should be “OnPush compatible”. It means, that every binding in your template is reactive.&lt;/p&gt;

&lt;p&gt;Reactive bindings will notify Angular that their value has changed, so the DOM might need to be modified.&lt;/p&gt;

&lt;p&gt;Examples of non-reactive bindings:&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="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
       &amp;lt;div&amp;gt; {{ name }} &amp;lt;/div&amp;gt;
       &amp;lt;child [value]="value"/&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;ExampleComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alice&lt;/span&gt;&lt;span class="dl"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bob&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;p&gt;The bindings &lt;code&gt;{{ name }}&lt;/code&gt; and &lt;code&gt;[value]=”value”&lt;/code&gt; lack reactivity — they won’t update if the values of name or value are modified because the template cannot know about it.&lt;/p&gt;

&lt;p&gt;Reactive bindings:&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="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
       &amp;lt;div&amp;gt; {{ name() }} &amp;lt;/div&amp;gt;
       &amp;lt;child [value]="value | async"/&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;ExampleComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;name&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="s2"&gt;Alice&lt;/span&gt;&lt;span class="dl"&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bob&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;p&gt;Here, the template will get a notification when &lt;code&gt;name&lt;/code&gt; or &lt;code&gt;value&lt;/code&gt; are updated. What happens in the template (what is marked as dirty, what is marked for traversal) — just implementation details, it doesn’t matter. What matters is: when notified about the changes, Angular knows what part of the views tree it should update.&lt;/p&gt;

&lt;p&gt;There are only two requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every binding in your templates should be reactive;&lt;/li&gt;
&lt;li&gt;Angular v17.1+.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No other things are required. If all components in your app have &lt;code&gt;changeDetection: ChangeDetectionStrategy.OnPush&lt;/code&gt; then your app will work fine in “zoneless” mode. There are many new things in the latest releases of Angular, but they are not required to be used to make your app zoneless.&lt;/p&gt;

&lt;h3&gt;
  
  
  Preparing your code
&lt;/h3&gt;

&lt;p&gt;NgZone has a few methods that your app or library may use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;onMicrotaskEmpty()&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onStable()&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onUnstable()&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onError()&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;run()&lt;/code&gt;, &lt;code&gt;runOutsideAngular()&lt;/code&gt;, &lt;code&gt;runGuarded()&lt;/code&gt;, &lt;code&gt;runTask()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;run*()&lt;/code&gt; methods are not needed in Zoneless Angular: you can just call your function directly.&lt;/p&gt;

&lt;p&gt;Was:&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleService&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;ngZone&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;NgZone&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nf"&gt;draw&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;ngZone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;runOutsideAngular&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;putPointsToCanvas&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;putPointsToCanvas&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;Now:&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;draw&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;putPointsToCanvas&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;putPointsToCanvas&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;To replace &lt;code&gt;onStable()&lt;/code&gt; and &lt;code&gt;onMicrotaskEmpty()&lt;/code&gt;, you can use &lt;code&gt;afterRender()&lt;/code&gt; or &lt;code&gt;afterNextRender()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;afterRender()&lt;/code&gt; will be called after every rendering of the application (not some component), and &lt;code&gt;afterNextRender()&lt;/code&gt; will be called after the next rendering event, once. Notice that both of them have &lt;a href="https://angular.dev/guide/components/lifecycle#afterrender-phases"&gt;phases&lt;/a&gt; (second argument).&lt;/p&gt;

&lt;p&gt;Was:&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleService&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;ngZone&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;NgZone&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nf"&gt;draw&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="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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ngZone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onStable&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;tap&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;putPointsToCanvas&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;private&lt;/span&gt; &lt;span class="nf"&gt;putPointsToCanvas&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;Now:&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleService&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;afterNextRender$&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;Subject&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;afterNextRender&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;afterNextRender$&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="p"&gt;}&lt;/span&gt;

      &lt;span class="nf"&gt;draw&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="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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;afterNextRender$&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;tap&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;putPointsToCanvas&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;private&lt;/span&gt; &lt;span class="nf"&gt;putPointsToCanvas&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;This code will work both in Zoneless and “regular” Angular.&lt;/p&gt;

&lt;p&gt;Notice that you can use &lt;code&gt;afterRender()&lt;/code&gt; and &lt;code&gt;afterNextRender()&lt;/code&gt; whenever you want; just call them in an injection context. Because, as the documentation says: “&lt;em&gt;The execution of render callbacks is not tied to any specific component instance, but instead an application-wide hook&lt;/em&gt;”.&lt;/p&gt;

&lt;p&gt;StackBlitz &lt;a href="https://stackblitz.com/edit/stackblitz-starters-rtpn9w?file=src%2Fmain.ts"&gt;example&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/stackblitz-starters-rtpn9w?ctl=1&amp;amp;embed=1&amp;amp;file=src%2Fmain.ts&amp;amp;hideExplorer=1&amp;amp;view=preview" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Third-party libraries
&lt;/h3&gt;

&lt;p&gt;The main purpose of this article is to help library maintainers in preparing their code for Zoneless Angular. But sometimes we use a library that is too large to fork, and we need to make it work in our application right now.&lt;/p&gt;

&lt;p&gt;For libraries that are not updated yet and use &lt;code&gt;onStable()&lt;/code&gt; or &lt;code&gt;onMicrotaskEmpty()&lt;/code&gt;, we can emulate the behavior of &lt;code&gt;onStable()&lt;/code&gt; and &lt;code&gt;onMicrotaskEmpty()&lt;/code&gt;, and later remove all of these emulations when all the libraries we use are ready for Zoneless Angular (or if and when Angular provides its own emulation).&lt;/p&gt;

&lt;p&gt;I’ve created a helper with functions that override the NoopNgZone implementation and emulate the &lt;code&gt;onStable()&lt;/code&gt; behavior: &lt;a href="https://gist.github.com/e-oz/4d64dd47699d3a63d15572ca49dc3db3"&gt;GitHub link&lt;/a&gt;. I don’t publish it as a library because it is a temporary solution.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I’ll repeat this because it is important: &lt;strong&gt;please update your apps and libraries to not rely on NgZone interface&lt;/strong&gt; (see above how to modify your code). Do not make your code rely on emulations made by this code snippet. Only use it to temporarily workaround limitations of the libraries you cannot modify.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let me explain how this emulation works:&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;NoopNgZone&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;NgZone&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&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;onStableEmitter&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;EventEmitter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&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="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;schedule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getCallbackScheduler&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;onStable&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;schedule&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;onStableEmitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&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;onStableEmitter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When code calls &lt;code&gt;NgZone.onStable()&lt;/code&gt;, our getter returns an Observable. Before returning it, we schedule an emission of the new value (which would mean that the zone is “stable”).&lt;/p&gt;

&lt;p&gt;For scheduling, I use awesome code I found in the Angular &lt;a href="https://github.com/angular/angular/blob/5328be6660b7ef388720edab4b3f2d0fa2699203/packages/core/src/util/callback_scheduler.ts"&gt;source code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Sometimes, libraries are so tightly bound to Zone.js that they expect &lt;code&gt;onStable()&lt;/code&gt; or &lt;code&gt;onMicrotaskEmpty()&lt;/code&gt; to emit quite often. For them, one event that we emit is not enough.&lt;/p&gt;

&lt;p&gt;To make them work, you can find an event after which that library wants to do its job and artificially emit &lt;code&gt;onStable()&lt;/code&gt; or &lt;code&gt;onMicrotaskEmpty()&lt;/code&gt; when this event happens:&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;ExampleComponent&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;ngZoneNoop&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;NgZone&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;NoopNgZone&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;docClickHandler&lt;/span&gt; &lt;span class="o"&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;ngZoneNoop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emitOnStable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;document&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;click&lt;/span&gt;&lt;span class="dl"&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;docClickHandler&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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&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;docClickHandler&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;In the example above, we are listening for click events and making our NgZone implementation emit &lt;code&gt;onStable&lt;/code&gt; event on every click.&lt;/p&gt;

&lt;p&gt;I hope you will never need to use a workaround like this, and all the libraries will quickly adapt to Zoneless Angular.&lt;/p&gt;

&lt;h3&gt;
  
  
  Converting our Angular app to zoneless
&lt;/h3&gt;

&lt;p&gt;This part is pretty easy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Provide a custom NgZone implementation and a scheduler:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="nf"&gt;bootstrapApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nf"&gt;ɵprovideZonelessChangeDetection&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="c1"&gt;// imported from `@angular/core`&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;ol&gt;
&lt;li&gt;Remove the import of zone.js in your polyfills.ts file, or (if you don’t have this file), remove the “zone.js” line from the polyfills array in the angular.json file.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s it!&lt;/p&gt;

&lt;p&gt;You can see that it doesn’t require a lot of changes if your app or lib is already “OnPush-compatible”.&lt;/p&gt;

&lt;p&gt;Authors of libraries, please consider making your code compatible with Zoneless Angular. It will not take a lot of effort: &lt;code&gt;afterRender()&lt;/code&gt; here, &lt;code&gt;afterNextRender()&lt;/code&gt; there and that’s it 😉&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Angular Team needs your &lt;a href="https://github.com/angular/angular/issues"&gt;feedback&lt;/a&gt;, they want to know about the cases that don’t work and where &lt;code&gt;afterRender()&lt;/code&gt; is not good enough. Let’s start preparing our codebases and provide them feedback!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I extend my heartfelt gratitude to the reviewers whose insightful comments and constructive feedback greatly contributed to the refinement of this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://twitter.com/lilbeqiri"&gt;Ilir Beqiri&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://twitter.com/Jean__Meche"&gt;Matthieu Riegler&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://twitter.com/rainerhahnekamp"&gt;Rainer Hahnekamp&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://twitter.com/tomastrajan"&gt;Tomas Trajan&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;🪽 Do you like this article? Share it and let it fly! 🛸&lt;/p&gt;

&lt;p&gt;💙 &lt;em&gt;If you enjoy my articles, consider &lt;a href="https://twitter.com/eugeniyoz"&gt;following me on Twitter&lt;/a&gt;, and/or &lt;a href="https://medium.com/@eugeniyoz"&gt;subscribing&lt;/a&gt; to receive my new articles by email.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Hacking Angular Signals</title>
      <dc:creator>Evgeniy OZ</dc:creator>
      <pubDate>Tue, 20 Feb 2024 09:45:01 +0000</pubDate>
      <link>https://forem.com/oz/hacking-angular-signals-2f7d</link>
      <guid>https://forem.com/oz/hacking-angular-signals-2f7d</guid>
      <description>&lt;p&gt;Let’s check out what Angular Signals have under the hood, and how we can use it for extending their functionality and debugging.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are Angular Signals
&lt;/h3&gt;

&lt;p&gt;Angular Signals are functions with methods:&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;$val&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="c1"&gt;// function:&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;$val&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// object:&lt;/span&gt;
    &lt;span class="nx"&gt;$val&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;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;$val&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="p"&gt;)&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;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 is this possible? Because in JavaScript, functions are objects:&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;// declaring a function&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;double&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;val&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;span class="c1"&gt;// adding a method&lt;/span&gt;
    &lt;span class="nx"&gt;double&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isEven&lt;/span&gt; &lt;span class="o"&gt;=&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="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;number&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// use as object&lt;/span&gt;
    &lt;span class="nx"&gt;double&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isEven&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;

    &lt;span class="c1"&gt;// use as function&lt;/span&gt;
    &lt;span class="nf"&gt;double&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// 16&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How can we use it?&lt;/p&gt;

&lt;p&gt;We can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;add new methods;&lt;/li&gt;
&lt;li&gt;override methods set() and update() to intercept modifications;&lt;/li&gt;
&lt;li&gt;read internal state variables and methods of signal;&lt;/li&gt;
&lt;li&gt;create a proxy signal that will intercept reads.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Extending our Signals
&lt;/h3&gt;

&lt;p&gt;Sometimes you need a variable to be a Signal, but some parts of your code would like to use it as an Observable instead.&lt;/p&gt;

&lt;p&gt;Fortunately, interfaces of Signals and Observables have no collisions in method names. So let’s create a hybrid:&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;function&lt;/span&gt; &lt;span class="nf"&gt;toObservableSignal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;s&lt;/span&gt;&lt;span class="p"&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;T&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;options&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ToObservableOptions&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="nf"&gt;isDevMode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;injector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;assertInInjectionContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toObservableSignal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="c1"&gt;// create an observable&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;toObservable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// add methods of observable to our signal object&lt;/span&gt;
      &lt;span class="k"&gt;for &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;obsKey&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;obs&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;s&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="nx"&gt;obsKey&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="nx"&gt;obs&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="nx"&gt;obsKey&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="nx"&gt;s&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;Usage &lt;a href="https://stackblitz.com/edit/stackblitz-starters-5xxadr?file=src%2Fmain.ts"&gt;example&lt;/a&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="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="c1"&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;h4&amp;gt;Signal A: {{ a() }}&amp;lt;/h4&amp;gt;
        &amp;lt;h4&amp;gt;Observable A: {{a|async}}&amp;lt;/h4&amp;gt;
        &amp;lt;h4&amp;gt;Signal C (computed() A*3): {{c()}}&amp;lt;/h4&amp;gt;

        {{quote()}}
      `&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;App&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;toObservableSignal&lt;/span&gt;&lt;span class="p"&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="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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

      &lt;span class="c1"&gt;// use as Observable&lt;/span&gt;
      &lt;span class="nx"&gt;b&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;a&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;debounceTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nf"&gt;distinctUntilChanged&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="nx"&gt;v&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;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&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://dummyjson.com/quotes/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// use as Signal&lt;/span&gt;
      &lt;span class="nx"&gt;c&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;a&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nx"&gt;quote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;toSignal&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;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// "a" will not stop being a Signal after &lt;/span&gt;
        &lt;span class="c1"&gt;// we used it as an Observable&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;a&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="p"&gt;)&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;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nf"&gt;decrement&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;a&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="p"&gt;)&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;max&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="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;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;You can find this function in the &lt;a href="https://github.com/nartc/ngxtension-platform"&gt;NG Extension Platform&lt;/a&gt;: &lt;a href="https://ngxtension.netlify.app/utilities/signals/to-observable-signal/"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This function can be improved in multiple ways, so your pull requests are welcomed!&lt;/p&gt;

&lt;p&gt;You can extend Signals with any functions you want, your fantasy here has almost no limitations: just don’t use names &lt;code&gt;set&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, and &lt;code&gt;asReadonly&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Overriding existing methods
&lt;/h3&gt;

&lt;p&gt;Let’s say that we want to intercept writes to our Signal to transform input values, duplicate information somewhere else, or just for debugging.&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;function&lt;/span&gt; &lt;span class="nf"&gt;skipNonEvenNumbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WritableSignal&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="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;srcSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// we need the source method to avoid recursion&lt;/span&gt;

      &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt; &lt;span class="o"&gt;=&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="kr"&gt;number&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="nx"&gt;value&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="mi"&gt;0&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;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[set] skipping:&lt;/span&gt;&lt;span class="dl"&gt;'&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;return&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;[set]:&lt;/span&gt;&lt;span class="dl"&gt;'&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="nf"&gt;srcSet&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="p"&gt;};&lt;/span&gt;
      &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updateFn&lt;/span&gt;&lt;span class="p"&gt;:&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="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;number&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;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;updateFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;s&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;value&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="mi"&gt;0&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;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[update] skipping:&lt;/span&gt;&lt;span class="dl"&gt;'&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;return&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;[update]:&lt;/span&gt;&lt;span class="dl"&gt;'&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="nf"&gt;srcSet&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="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;Usage &lt;a href="https://stackblitz.com/edit/stackblitz-starters-yyd2rc?devToolsHeight=50&amp;amp;file=src%2Fmain.ts"&gt;example&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This trick is being used in &lt;a href="https://github.com/e-oz/ngx-reactive-storage/"&gt;Reactive Storage&lt;/a&gt;: &lt;a href="https://github.com/e-oz/ngx-reactive-storage/blob/main/projects/ngx-reactive-storage/src/lib/observer.ts#L92"&gt;getWritableSignal()&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inside a Signal
&lt;/h3&gt;

&lt;p&gt;Angular Signal is not just a function, it is an object. This object has a hidden field, &lt;code&gt;SIGNAL&lt;/code&gt;, which contains some interesting data and functions. I’m glad we have it, and I hope you will not abuse it. Because the tricks above were “a little bit hacky”, and the tricks below are too filthy to use for anything but debugging, creating dev tools, and fun.&lt;/p&gt;

&lt;p&gt;Every Angular Signal extends ReactiveNode:&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;// packages/core/primitives/signals/src/graph.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;REACTIVE_NODE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ReactiveNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;lastCleanEpoch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;dirty&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="na"&gt;producerNode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;producerLastReadVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;producerIndexOfThis&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;nextProducerIndex&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="na"&gt;liveConsumerNode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;liveConsumerIndexOfThis&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;consumerAllowSignalWrites&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="na"&gt;consumerIsAlwaysLive&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="na"&gt;producerMustRecompute&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="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;producerRecomputeValue&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;consumerMarkedDirty&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;consumerOnSignalRead&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;this way:&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;// packages/core/primitives/signals/src/signal.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;SIGNAL_NODE&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="nx"&gt;REACTIVE_NODE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;defaultEquals&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="kc"&gt;undefined&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;But an instantiated Signal object does not contain all of this directly. All of them are hidden under the field that uses a Symbol as a name:&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;// packages/core/primitives/signals/src/signal.ts&lt;/span&gt;

    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createSignal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;initialValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;SignalGetter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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="na"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SignalNode&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SIGNAL_NODE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;node&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;initialValue&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;getter&lt;/span&gt; &lt;span class="o"&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="nf"&gt;producerAccessed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&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;node&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="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;SignalGetter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;// next line adds a SignalNode to the field SIGNAL:&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getter&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;node&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;getter&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;So if you have a signal $value and you access &lt;code&gt;SIGNAL&lt;/code&gt; field, then you’ll get all of the fields that &lt;code&gt;SIGNAL_NODE&lt;/code&gt; has.&lt;/p&gt;

&lt;p&gt;How can we use it?&lt;/p&gt;

&lt;p&gt;We can &lt;a href="https://stackblitz.com/edit/stackblitz-starters-8xzgwj?file=src%2Fmain.ts"&gt;read fields&lt;/a&gt; and override methods to intercept access and use it for debugging or to create fancy tools that illustrate what is going on inside a Signal and render the &lt;a href="https://medium.com/@eugeniyoz/dependency-graph-in-angular-signals-53ee47f75e21"&gt;Dependency Graph&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We can even convert some fields to accessors:&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;function&lt;/span&gt; &lt;span class="nf"&gt;getSignalVersion&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WritableSignal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;Signal&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;$version&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="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;version&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;get&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;untracked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$version&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;🟢 reading:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;v&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;v&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&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;untracked&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;$version&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;v&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;🔴 writing:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;v&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;return&lt;/span&gt; &lt;span class="nx"&gt;$version&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://stackblitz.com/edit/stackblitz-starters-scbktp?file=src%2Fmain.ts"&gt;StackBlitz&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Or create a proxy that can watch Signal reads without &lt;code&gt;effect()&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;watchSignalReads&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;M&lt;/span&gt; &lt;span class="kd"&gt;extends&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;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;WritableSignal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&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;M&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;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newGetter&lt;/span&gt; &lt;span class="o"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;s&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;Read:&lt;/span&gt;&lt;span class="dl"&gt;'&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;return&lt;/span&gt; &lt;span class="nx"&gt;value&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;newGetter&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;node&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;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasOwnProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;set&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;WritableSignal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;newGetter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;newGetter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;newGetter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asReadonly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asReadonly&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="nx"&gt;newGetter&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;M&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;Usage &lt;a href="https://stackblitz.com/edit/stackblitz-starters-jn29gy?devToolsHeight=70&amp;amp;file=src%2Fmain.ts"&gt;example&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Again, I hope you won’t even consider using this in “production,” and instead, I hope you’ll utilize it to create some amazing tools, gain recognition, and contribute to enriching the Angular ecosystem 😎&lt;/p&gt;




&lt;p&gt;🪽 Do you like this article? Share it and let it fly! 🛸&lt;/p&gt;

&lt;p&gt;💙 &lt;em&gt;If you enjoy my articles, consider &lt;a href="https://twitter.com/eugeniyoz"&gt;following me on Twitter&lt;/a&gt;, and/or &lt;a href="https://medium.com/@eugeniyoz"&gt;subscribing&lt;/a&gt; to receive my new articles by email.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1759212371770245614-589" src="https://platform.twitter.com/embed/Tweet.html?id=1759212371770245614"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1759212371770245614-589');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1759212371770245614&amp;amp;theme=dark"
  }



&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Creating Angular Components: Template-First Declarative Approach</title>
      <dc:creator>Evgeniy OZ</dc:creator>
      <pubDate>Tue, 06 Feb 2024 11:56:19 +0000</pubDate>
      <link>https://forem.com/oz/creating-angular-components-template-first-declarative-approach-pai</link>
      <guid>https://forem.com/oz/creating-angular-components-template-first-declarative-approach-pai</guid>
      <description>&lt;p&gt;This article explains how to build a reactive and reusable Angular component in a declarative way, using a “template-first” approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  So, we need a component!
&lt;/h3&gt;

&lt;p&gt;We need to display a table of items, with pagination, each column should be sortable in ascending or descending order.&lt;/p&gt;

&lt;p&gt;Let’s use &lt;code&gt;ng g c items-table&lt;/code&gt; to generate a component, and then add file items-table.store.ts to the folder, generated by Angular CLI. If you don’t know why I call it “store”, &lt;a href="https://medium.com/@eugeniyoz/application-state-management-with-angular-signals-b9c8b3a3afd7"&gt;this article&lt;/a&gt; is for you.&lt;/p&gt;

&lt;p&gt;I recommend using stores for non-trivial components and moving most of the logic there. This way it will be much easier to reuse code (not bound to the template anymore) and to communicate from child components. &lt;br&gt;
It is not so significant detail for the approach I’m describing in this article: if you prefer to put it all into the component itself — I don’t mind at all.&lt;/p&gt;

&lt;p&gt;An important part of this approach is to start creating the template first, not anything else.&lt;/p&gt;

&lt;p&gt;We have an empty template, generated by Angular CLI:&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;p&amp;gt;&lt;/span&gt;items-table works!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need a table, so let’s put a table here:&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;table&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"table table-sm table-striped"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;thead&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
        @for (header of store.$headers(); track header.path) {
        }
      &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/thead&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your IDE will start complaining that you don’t have &lt;code&gt;store.$headers()&lt;/code&gt; yet. But let’s ignore it for now and just keep creating our template — it is better to don’t interrupt this process and express what we need in the template first, without thinking about the 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;table&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"table table-sm table-striped"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;thead&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
        @for (header of store.$headers(); track header.path) {
          &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;(click)=&lt;/span&gt;&lt;span class="s"&gt;"store.changeSorting(header.path)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"d-flex flex-row align-items-center gap-2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;{{ header.label }}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
              @if (store.$sortByHeader() === header.path) {
                @if (store.$sortingOrder() === 'asc') {
                  &lt;span class="nt"&gt;&amp;lt;ng-container&lt;/span&gt; &lt;span class="na"&gt;*ngTemplateOutlet=&lt;/span&gt;&lt;span class="s"&gt;"iconSortDown"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;
                } @else {
                  @if (store.$sortingOrder() === 'desc') {
                    &lt;span class="nt"&gt;&amp;lt;ng-container&lt;/span&gt; &lt;span class="na"&gt;*ngTemplateOutlet=&lt;/span&gt;&lt;span class="s"&gt;"iconSortUp"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;
                  }
                }
              }
            &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
        }
      &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/thead&amp;gt;&lt;/span&gt;

      &lt;span class="nt"&gt;&amp;lt;tbody&amp;gt;&lt;/span&gt;
        @for (item of store.$items(); track item) {
          &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
            @for (header of store.$headers(); track header.path) {
              &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;{{ item[header.path] }}&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
            }
          &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
        }
      &lt;span class="nt"&gt;&amp;lt;/tbody&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- Pagination --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"d-flex flex-row justify-content-center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn-group"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-outline-primary"&lt;/span&gt; &lt;span class="na"&gt;(click)=&lt;/span&gt;&lt;span class="s"&gt;"store.prevPage()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;⬅️&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-primary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ store.$page() + 1 }}&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-outline-primary"&lt;/span&gt; &lt;span class="na"&gt;(click)=&lt;/span&gt;&lt;span class="s"&gt;"store.nextPage()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;➡️&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &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;Now we’ve declared in our component what we need to render it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can find the code, described in this article, in this repository: &lt;a href="https://github.com/e-oz/template-first-declarative"&gt;🔗 GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, we can start implementing all the data bindings and events handlers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reactive Data Bindings
&lt;/h3&gt;

&lt;p&gt;I recommend using Signals in Angular templates as the reactive containers of data.&lt;/p&gt;

&lt;p&gt;The first signal we need to create is &lt;code&gt;store.$headers()&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="c1"&gt;// items-table.store.ts&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;ItemsTableHeader&lt;/span&gt; &lt;span class="o"&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="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;label&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="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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ItemsTableStore&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;$headers&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;ItemsTableHeader&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next highlighted thing is an event handler, but let’s postpone it for now, and take the next signals: &lt;code&gt;$sortByHeader()&lt;/code&gt; and &lt;code&gt;$sortingOrder()&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="c1"&gt;// items-table.store.ts&lt;/span&gt;

    &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;$sortByHeader&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="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;undefined&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;$sortingOrder&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;asc&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;desc&lt;/span&gt;&lt;span class="dl"&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;asc&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;And now, the most interesting part, &lt;code&gt;$items()&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;We could naively implement it like this:&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;readonly&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But, then for pagination and sorting we would need to overwrite the value of that signal. It is an imperative approach, and it is not good enough for us: this way $items would have multiple sources of truth: component input, pagination side effects, and sorting. They all would write into our signal, and we would have to control in what order they should do this…&lt;/p&gt;

&lt;p&gt;The imperative approach is only simpler when the first line is written, later imperative code evolves into a more and more complicated mess.&lt;/p&gt;

&lt;p&gt;Let’s use the declarative approach instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Derived values
&lt;/h3&gt;

&lt;p&gt;The initial source of items is the component’s inputs — and we should react to the changes in this input too:&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="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;items-table&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// ...&lt;/span&gt;
      &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ItemsTableStore&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;ItemsTableComponent&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;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;ItemsTableStore&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="na"&gt;required&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="kd"&gt;set&lt;/span&gt; &lt;span class="nf"&gt;items&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="k"&gt;if &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="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;setItems&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="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;When we produce the list of items, the last thing that will decide what items we should render on this page is pagination.&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;// items-table.store.ts&lt;/span&gt;

      &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;$itemsPerPage&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="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="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;$page&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="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="mi"&gt;0&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;$inputItems&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="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;$items&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="kd"&gt;const&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="nf"&gt;$inputItems&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="c1"&gt;// pagination:&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page&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="nf"&gt;$page&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;perPage&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="nf"&gt;$itemsPerPage&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;page&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&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;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;perPage&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="nx"&gt;items&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="nx"&gt;items&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="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;perPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;perPage&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;perPage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="nf"&gt;setItems&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$inputItems&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;items&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Items should be sorted, in selected order, and sorting should happen before pagination, otherwise, we’ll only sort items on the selected page.&lt;/p&gt;

&lt;p&gt;So let’s create a computed signal that will produce sorted items from &lt;code&gt;$inputItems()&lt;/code&gt;, and our paginated &lt;code&gt;$items()&lt;/code&gt; will use that produced result as input:&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;// items-table.store.ts&lt;/span&gt;

      &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;$sortedItems&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sortPath&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="nf"&gt;$sortByHeader&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="nx"&gt;sortPath&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="nf"&gt;$inputItems&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;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="nf"&gt;$inputItems&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="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&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;aVal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sortPath&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;bVal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sortPath&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;typeof&lt;/span&gt; &lt;span class="nx"&gt;aVal&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;bVal&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;number&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;aVal&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;bVal&lt;/span&gt; &lt;span class="p"&gt;?&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;aVal&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;bVal&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sortPath&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;localeCompare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sortPath&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;toString&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;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="nf"&gt;$sortingOrder&lt;/span&gt;&lt;span class="p"&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;asc&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reverse&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;readonly&lt;/span&gt; &lt;span class="nx"&gt;$items&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="kd"&gt;const&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="nf"&gt;$sortedItems&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="c1"&gt;// pagination:&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All the data bindings are implemented, let’s implement event handlers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Side Effects
&lt;/h3&gt;

&lt;p&gt;The first event handler, &lt;code&gt;changeSorting()&lt;/code&gt;, is a function that will return nothing but after its execution, the state of our store will be modified — it is a &lt;a href="https://en.wikipedia.org/wiki/Side_effect_(computer_science)"&gt;side effect&lt;/a&gt; of that function, and often such functions are called “side effects” (or “effects”) for brevity.&lt;/p&gt;

&lt;p&gt;Side effects are the only place where our imperative code should be located. As you might noticed, all the &lt;code&gt;computed()&lt;/code&gt; signals just return the result, based on inputs, and don’t have side effects (they don’t write to signals). It makes them pure functions. Writing to signals is not allowed in &lt;code&gt;computed()&lt;/code&gt; exactly to make them pure functions. I recommend using &lt;code&gt;computed()&lt;/code&gt; because of this — your code will be declarative and clean.&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;// items-table.store.ts&lt;/span&gt;

      &lt;span class="nf"&gt;changeSorting&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="kr"&gt;keyof&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&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="nf"&gt;$sortByHeader&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$sortingOrder&lt;/span&gt;&lt;span class="p"&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;asc&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$sortingOrder&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;desc&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="k"&gt;else&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;$sortByHeader&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;undefined&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;else&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;$sortByHeader&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;path&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;$sortingOrder&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;asc&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;Handlers prevPage() and nextPage() are 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;// items-table.store.ts&lt;/span&gt;

      &lt;span class="nf"&gt;prevPage&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;page&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="nf"&gt;$page&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;page&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="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;$page&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;page&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="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nf"&gt;nextPage&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;page&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="nf"&gt;$page&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;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="nf"&gt;$sortedItems&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;items&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="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;page&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="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="nf"&gt;$itemsPerPage&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;$page&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;page&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="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;I omitted the implementation of headers input of our component in the article, but you can find it in the source code (it is too simple to be illustrative).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That’s it!&lt;br&gt;
Now our component will render a table of items, and the content of this table is reactive — it will be modified in response to user actions.&lt;/p&gt;




&lt;p&gt;In the &lt;a href="https://github.com/e-oz/template-first-declarative"&gt;source code&lt;/a&gt;, you can check out how the parent component (app.component.ts) uses our component. Also, if you open the resulting app in multiple tabs, and start switching “collections”, you’ll see they all synced across tabs, using just 1 line of code 😎&lt;/p&gt;

&lt;p&gt;You can play with the deployed app using &lt;a href="https://e-oz.github.io/template-first-declarative/"&gt;this link&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;🪽 Do you like this article? Share it and let it fly! 🛸&lt;/p&gt;

&lt;p&gt;💙 &lt;em&gt;If you enjoy my articles, consider &lt;a href="https://twitter.com/eugeniyoz"&gt;following me on Twitter&lt;/a&gt;, and/or &lt;a href="https://medium.com/@eugeniyoz"&gt;subscribing&lt;/a&gt; to receive my new articles by email.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>angular</category>
    </item>
    <item>
      <title>Globally Shared Instances in Angular — Use with Care</title>
      <dc:creator>Evgeniy OZ</dc:creator>
      <pubDate>Tue, 06 Feb 2024 11:52:22 +0000</pubDate>
      <link>https://forem.com/oz/globally-shared-instances-in-angular-use-with-care-4pio</link>
      <guid>https://forem.com/oz/globally-shared-instances-in-angular-use-with-care-4pio</guid>
      <description>&lt;p&gt;Why you should use &lt;code&gt;{providedIn: “root”}&lt;/code&gt; not always, not by default, but only when you need it and know how to use it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why do we need the &lt;code&gt;Injectable()&lt;/code&gt; decorator?
&lt;/h3&gt;

&lt;p&gt;To let the Angular Dependency Injection mechanism inject it. So by definition, if you decorate your class with the &lt;code&gt;Injectable()&lt;/code&gt;, you want to later use it in your components (or other services), and let Angular DI take care of the dependencies of this decorated class.&lt;/p&gt;

&lt;p&gt;There is one configurable option: &lt;code&gt;providedIn&lt;/code&gt;, which currently has only 2 meaningful values: &lt;code&gt;root&lt;/code&gt; and &lt;code&gt;undefined&lt;/code&gt; (default).&lt;/p&gt;

&lt;p&gt;Services with &lt;code&gt;providedIn: root&lt;/code&gt; will be instantiated just once. Without this option — will be instantiated every time, when a component that has them in its &lt;code&gt;providers&lt;/code&gt; array is instantiated. That is an important difference.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why ‘use with care’?
&lt;/h3&gt;

&lt;p&gt;Services, &lt;code&gt;providedIn: root&lt;/code&gt; will be shared across your application. It means, that every component, every service that injects such services, will get the same instance. It is not “bad”, or “wrong”, it just means that you should write the code in such services with constant consideration, that multiple components will use it at the same time.&lt;/p&gt;

&lt;p&gt;Sometimes it is exactly what you need! For example, &lt;code&gt;HttpClient&lt;/code&gt; with its interceptors. You want to configure them once and use the same instance of &lt;code&gt;HttpClient&lt;/code&gt; across the whole application.&lt;/p&gt;

&lt;p&gt;But quite often developers just add it because tutorials told them to, and they don’t know other ways of injecting a service. And not every time developers are actually aware of the fact that multiple components will share the same instance of the service they create.&lt;/p&gt;

&lt;p&gt;Here is a &lt;strong&gt;modified&lt;/strong&gt; example from Angular &lt;a href="https://angular.dev/essentials/sharing-logic"&gt;documentation&lt;/a&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;Injectable&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;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="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;CalculatorService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;scale&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="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&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="nx"&gt;y&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="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;y&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;scale&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;If some component modifies the scale field, all other components that use this service will be affected. It is a simplified example, in the real code things are more sophisticated.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to use it correctly?
&lt;/h3&gt;

&lt;p&gt;The main rule of globally shared services: they should either not have an internal state, or their state should not be modifiable after instantiation, or their code should be aware that multiple different consumers will modify this state in a chaotic order (that’s why methods that modify the state should be atomic — only one call should be expected from a consumer, not a set of calls, executed in pre-defined order).&lt;/p&gt;

&lt;p&gt;I’m not saying “do not use it”, but: if you want to share the single instance of that service with all the components that use it — do it, and write the code accordingly.&lt;/p&gt;

&lt;p&gt;If you want a new instance of this class whenever some component is instantiated, and have it destroyed when a component is destroyed — do not add &lt;code&gt;providedIn: root&lt;/code&gt;, just add &lt;code&gt;Injectable()&lt;/code&gt; and add this service to the &lt;code&gt;providers&lt;/code&gt; array of that component.&lt;/p&gt;

&lt;p&gt;If your class has no dependencies and you don’t need it to be shared across multiple components — then you don’t even need the &lt;code&gt;Injectable()&lt;/code&gt; decorator, you can just use new.&lt;/p&gt;

&lt;p&gt;In my article &lt;a href="https://medium.com/@eugeniyoz/advanced-usage-of-angular-dependency-injection-399d0a67a938"&gt;Advanced Usage of Angular Dependency Injection&lt;/a&gt; you can find more examples of using Angular DI in your apps.&lt;/p&gt;




&lt;p&gt;🪽 Do you like this article? Share it and let it fly! 🛸&lt;/p&gt;

&lt;p&gt;💙 &lt;em&gt;If you enjoy my articles, consider &lt;a href="https://twitter.com/eugeniyoz"&gt;following me on Twitter&lt;/a&gt;, and/or &lt;a href="https://medium.com/@eugeniyoz"&gt;subscribing&lt;/a&gt; to receive my new articles by email.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Hidden Reactivity Tricks in Angular Templates</title>
      <dc:creator>Evgeniy OZ</dc:creator>
      <pubDate>Tue, 06 Feb 2024 11:45:28 +0000</pubDate>
      <link>https://forem.com/oz/hidden-reactivity-tricks-in-angular-templates-25g2</link>
      <guid>https://forem.com/oz/hidden-reactivity-tricks-in-angular-templates-25g2</guid>
      <description>&lt;p&gt;Let me show you some tricks you can use to add reactivity to your templates, even when it looks impossible.&lt;/p&gt;

&lt;p&gt;I’ll show you how to make any field of an object reactive, and you will not even need the async pipe to get the updates.&lt;/p&gt;

&lt;p&gt;Let’s start with a simple template:&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;ul&amp;gt;&lt;/span&gt;
      @for(item of items; track item.id) {
        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;{{ item.name() }}: {{ item.id }}&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
      }
    &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the type of “item” objects:&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;type&lt;/span&gt; &lt;span class="nx"&gt;Item&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="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;id&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, &lt;code&gt;name&lt;/code&gt; can be updated synchronously, &lt;code&gt;id&lt;/code&gt; can not be updated at all.&lt;/p&gt;

&lt;p&gt;But what if I tell you, that both of them can be reactive? And you can update them any way you need: synchronously or asynchronously.&lt;/p&gt;

&lt;p&gt;When Angular reads signals in a template, the template becomes a consumer of these signals. And whenever you update these signals, the template will be notified. It is a simple concept to grasp.&lt;/p&gt;

&lt;p&gt;But there is more: when a template calls some function to get its value, and this function reads a signal — the template still becomes a consumer of that signal. And the level of nesting doesn’t matter! Only two things can prevent it: if you make an asynchronous call, or if you wrap your call with &lt;code&gt;untracked()&lt;/code&gt;.&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="p"&gt;{{&lt;/span&gt; &lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;

    &lt;span class="nx"&gt;$user&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;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;John Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nf"&gt;name&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="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;firstName&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;lastName&lt;/span&gt;&lt;span class="p"&gt;()].&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &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="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;firstName&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="nf"&gt;getNameParts&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="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;lastName&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="nf"&gt;getNameParts&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="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;getNameParts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// here we read a signal!&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="nf"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &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="nf"&gt;updateUser&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;$user&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="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;Jane Doe&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;p&gt;Here you can see 3 levels of nested calls before we read the signal. Two levels of function don’t know anything about the signal. And still, because the last one reads the signal, all of them will be called by the template again, after the signal is updated.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Yes, the code of this example is not perfect — it was made intentionally, to illustrate the idea.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Asynchronous reactivity using synchronous function call
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&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="o"&gt;=&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;repeat$&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;2000&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;$repeat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;toSignal&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;repeat$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;initialValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&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="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&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="kd"&gt;const&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="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="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Item &lt;/span&gt;&lt;span class="dl"&gt;'&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="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&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;:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;repeat&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;$repeat&lt;/span&gt;&lt;span class="p"&gt;()&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="na"&gt;id&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="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;push&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;Here we have a source of asynchronous data: observable &lt;code&gt;repeat$&lt;/code&gt;.&lt;br&gt;
We convert it into a signal, that can be read synchronously: &lt;code&gt;$repeat&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When we populate the items array, we assign a function to the name field, that reads the &lt;code&gt;$repeat&lt;/code&gt; signal every time it is called.&lt;/p&gt;

&lt;p&gt;And because it is a signal, our template will become a consumer of this signal when &lt;code&gt;name()&lt;/code&gt; is called! After that, whenever $repeat is updated, our template will be notified.&lt;/p&gt;

&lt;p&gt;The source of data is asynchronous, but you don’t need async pipe to get the update notifications.&lt;/p&gt;

&lt;p&gt;Because Angular Signals match the signature of a callback &lt;code&gt;() =&amp;gt; T&lt;/code&gt;, you can just use signals to add reactivity when a callback function is accepted as a value for a field.&lt;/p&gt;
&lt;h3&gt;
  
  
  Replacing fields with getters to make them reactive
&lt;/h3&gt;

&lt;p&gt;Field id also can be reactive — we can replace it with a getter in our object, and this getter will read a signal:&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;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;$offset&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="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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&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="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;$id&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="nx"&gt;i&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="nf"&gt;$offset&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;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Item&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="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Item &lt;/span&gt;&lt;span class="dl"&gt;'&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="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&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;:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;repeat&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;$repeat&lt;/span&gt;&lt;span class="p"&gt;()&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="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;id&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="nf"&gt;$id&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;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;push&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;Now, when the template reads id, it becomes a consumer of &lt;code&gt;$id&lt;/code&gt; — a signal, created using &lt;code&gt;computed()&lt;/code&gt;, which reads the signal &lt;code&gt;$offset&lt;/code&gt;. Whenever $offset is updated, &lt;code&gt;$id&lt;/code&gt; is notified and this signal notifies the template.&lt;/p&gt;

&lt;p&gt;This trick might become &lt;em&gt;very&lt;/em&gt; useful if you need to add reactivity to some part of an existing template, and migrating it to signals or observables is too expensive or too dangerous.&lt;/p&gt;

&lt;h3&gt;
  
  
  Combining Signals with Observables
&lt;/h3&gt;

&lt;p&gt;Quite often we need more complicated sources of asynchronous data, than just &lt;code&gt;timer()&lt;/code&gt;.&lt;br&gt;
The most common source of asynchronous data is HTTP requests. Let me show you how you can easily combine Signals and Observables to get the ultimate power.&lt;/p&gt;

&lt;p&gt;Template:&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;p&amp;gt;&lt;/span&gt;Current temperature in Barcelona: {{temp()}}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;(click)=&lt;/span&gt;&lt;span class="s"&gt;"readTemp()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Check Temperature&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Component:&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;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;reloadTemp$&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="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;$tempIsLoading&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;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="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;http&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;HttpClient&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nf"&gt;readTemp&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;reloadTemp$&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="p"&gt;}&lt;/span&gt;

      &lt;span class="c1"&gt;// observable becomes a signal&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;$weather&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;toSignal&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;reloadTemp$&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;startWith&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$tempIsLoading&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getWeather&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;http&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;finalize&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;$tempIsLoading&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="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;initialValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// consumer of $weather&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;$temp&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;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="nf"&gt;$tempIsLoading&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Checking...&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="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;w&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&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="nf"&gt;$weather&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="nx"&gt;w&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;w&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;temperature_2m&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;℃&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="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;getTemperature&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="nf"&gt;$temp&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="nf"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// just to illustrate the fact,&lt;/span&gt;
        &lt;span class="c1"&gt;// that this function does not know &lt;/span&gt;
        &lt;span class="c1"&gt;// anything about the signal it will use.&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="nf"&gt;getTemperature&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;You can find the full code of all these examples and play with this app: &lt;a href="https://stackblitz.com/edit/stackblitz-starters-wnebqr?file=src%2Fmain.ts"&gt;StackBlitz&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/stackblitz-starters-wnebqr?file=src%2Fmain.ts" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Using tricks like these, you can add reactivity to the places where it was impossible to start thinking about, and most of the time you will not even need to modify a template.&lt;/p&gt;




&lt;p&gt;🪽 Do you like this article? Share it and let it fly! 🛸&lt;/p&gt;

&lt;p&gt;💙 &lt;em&gt;If you enjoy my articles, consider &lt;a href="https://twitter.com/eugeniyoz"&gt;following me on Twitter&lt;/a&gt;, and/or &lt;a href="https://medium.com/@eugeniyoz"&gt;subscribing&lt;/a&gt; to receive my new articles by email.&lt;/em&gt;&lt;/p&gt;

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