<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Ninja Squad Blog</title>
  <link href="https://blog.ninja-squad.com/atom.xml" rel="self"/>
  <link href="https://blog.ninja-squad.com"/>
  <updated>2026-02-27T10:58:30.485Z</updated>
  <id>https://blog.ninja-squad.com/</id>
  <author>
    <name>Ninja Squad</name>
    <email>contact@ninja-squad.com</email>
  </author>
  <entry>
    <title>What&apos;s new in Angular 21.2?</title>
    <link href="https://blog.ninja-squad.com/2026/02/26/what-is-new-angular-21.2"/>
    <updated>2026-02-26T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2026/02/26/what-is-new-angular-21.2</id>
    <content type="html">
      &lt;p&gt;Angular&amp;nbsp;21.2.0 is here!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;a href=&quot;https://github.com/angular/angular/releases/tag/v21.2.0&quot;&gt;
    &lt;img class=&quot;img-fluid&quot; style=&quot;max-width: 60%&quot; src=&quot;/assets/images/angular_gradient.webp&quot; alt=&quot;Angular logo&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Angular 21.2 is the second minor release of the v21 cycle.
Let&amp;#39;s dive in!&lt;/p&gt;
&lt;h2&gt;Templates&lt;/h2&gt;
&lt;h3&gt;Arrow functions&lt;/h3&gt;
&lt;p&gt;One of the most requested template syntax improvements is finally here:
we can now use arrow functions directly in templates.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; (click)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;count.update(n =&gt; n + 1)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;+1&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that you can&amp;#39;t use an arrow function in an event listener to call a method.
&lt;code&gt;(click)=&amp;quot;() =&amp;gt; doSomething()&amp;quot;&lt;/code&gt; will not work, and will throw the following error at compile time:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;Arrow&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; will&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; not&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; be&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; invoked&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; event&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; listener.&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; Did&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; you&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; intend&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; call&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; a&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; method?&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;instanceof&lt;/code&gt; is now also supported in templates,
but I don&amp;#39;t think we ever missed this one 🤷.&lt;/p&gt;
&lt;h3&gt;Exhaustive &lt;code&gt;@switch&lt;/code&gt; checks&lt;/h3&gt;
&lt;p&gt;Angular now supports exhaustive type-checking for control-flow &lt;code&gt;@switch&lt;/code&gt; blocks.
You can opt in by ending the switch with &lt;code&gt;@default never;&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@switch&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  @case&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;idle&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Idle&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  @case&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;loading&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Loading&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  @default&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; never;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If &lt;code&gt;status()&lt;/code&gt; can also be another value (for example &lt;code&gt;&amp;#39;error&amp;#39;&lt;/code&gt;),
the template type-checker now reports it at compile time:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;ERROR&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; TS2322: Type &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;&quot;error&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; is not assignable to type &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;never&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;. &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;plugin angular-compiler&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;    src/app/live/live.html:7:13:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;      7&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; │&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;     @switch&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (status()) {&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&amp;#39;m super happy to see this landing,
as I opened the original feature request when the control flow syntax was announced, back in 2023 😍.&lt;/p&gt;
&lt;h2&gt;ChangeDetectionStrategy.Eager&lt;/h2&gt;
&lt;p&gt;No, this is not a &lt;em&gt;new&lt;/em&gt; change detection strategy,
but an alias for &lt;code&gt;ChangeDetectionStrategy.Default&lt;/code&gt;.
This is part of the ongoing effort to change the default change detection strategy to &lt;code&gt;OnPush&lt;/code&gt;,
as you can read in the &lt;a href=&quot;https://github.com/angular/angular/discussions/66779&quot;&gt;official RFC&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the next major release, the default change detection strategy will be switched to &lt;code&gt;OnPush&lt;/code&gt;,
and the &lt;code&gt;Eager&lt;/code&gt; alias will be the only way to explicitly opt in to the old default behavior (&lt;code&gt;Default&lt;/code&gt; is marked as deprecated in v21.1).
That means components with no specified change detection strategy will be using &lt;code&gt;OnPush&lt;/code&gt;
and we&amp;#39;ll have to explicitly set &lt;code&gt;ChangeDetectionStrategy.Eager&lt;/code&gt; for components that are not &lt;code&gt;OnPush&lt;/code&gt; compatible.
An automatic migration will take care of that for existing components.&lt;/p&gt;
&lt;h2&gt;Resource snapshot&lt;/h2&gt;
&lt;p&gt;Angular now exposes a resource state as a first-class value with &lt;code&gt;ResourceSnapshot&amp;lt;T&amp;gt;&lt;/code&gt;.
A resource has a new &lt;code&gt;snapshot()&lt;/code&gt; signal,
which is a simple object containing a &lt;code&gt;status&lt;/code&gt; and either a &lt;code&gt;value&lt;/code&gt; or an &lt;code&gt;error&lt;/code&gt;.
Angular also introduces &lt;code&gt;resourceFromSnapshots(...)&lt;/code&gt; to turn a snapshot signal back into a &lt;code&gt;Resource&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is an advanced API that allows you to customize the behavior of resources.
You can use normal signal composition (&lt;code&gt;computed&lt;/code&gt;, &lt;code&gt;linkedSignal&lt;/code&gt;) to transform resource states,
then convert the result back to a resource.
This pattern makes it much easier to build reusable resource utilities.
For example, built-in resources set the value to &lt;code&gt;undefined&lt;/code&gt; when loading.
If you don&amp;#39;t like this behavior, you can implement a resource that keeps the stale value while loading.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; withPreviousValue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; Resource&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;):&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; Resource&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; derived&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; linkedSignal&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ResourceSnapshot&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ResourceSnapshot&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    source&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;snapshot&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    computation&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;snap&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; previous&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;      if&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;snap&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ===&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;loading&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; previous&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;?.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;?.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ===&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;resolved&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;        // keep previous value while loading next one&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;loading&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; previous&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;      return&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; snap&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; resourceFromSnapshots&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;derived&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Signal Forms&lt;/h2&gt;
&lt;p&gt;Signal Forms received several improvements in Angular v21.2.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;FormRoot&lt;/code&gt; directive and &lt;code&gt;submission&lt;/code&gt; option&lt;/h3&gt;
&lt;p&gt;One of the interesting Signal Forms additions in v21.2
is the &lt;code&gt;FormRoot&lt;/code&gt; directive.
Instead of manually handling &lt;code&gt;(submit)&lt;/code&gt; and calling &lt;code&gt;submit(...)&lt;/code&gt;,
you can now bind the form directly in the template:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [formRoot]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;loginForm&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [formField]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;loginForm.login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;submit&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Log in&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Submission logic can be declared in the &lt;code&gt;form()&lt;/code&gt; configuration directly:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;protected readonly loginForm &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; form&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;credentials&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  submission&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    action&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;userService&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;authenticate&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;credentials&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;credentials&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;password)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    onInvalid&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;invalidSubmission&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    ignoreValidators&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;none&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, this &lt;code&gt;submission&lt;/code&gt; option also allows to define an &lt;code&gt;onInvalid&lt;/code&gt; callback,
which is called when the form is submitted while invalid.
The &lt;code&gt;ignoreValidators&lt;/code&gt; option let you define whether the validation
should be ignored when submitting the form or not:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pending&lt;/code&gt; (default value) ignore pending async validators, but not synchronous validators;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;all&lt;/code&gt; ignore all validators;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;none&lt;/code&gt; don&amp;#39;t ignore any validator.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;FormRoot&lt;/code&gt; directive also automatically adds the &lt;code&gt;novalidate&lt;/code&gt; attribute to the form element,
preventing native browser validation from interfering with Signal Forms validation.&lt;/p&gt;
&lt;p&gt;Note that the existing &lt;code&gt;submit()&lt;/code&gt; function now uses these form-level defaults.
So if &lt;code&gt;action&lt;/code&gt; is defined in &lt;code&gt;submission&lt;/code&gt;,
you no longer need to pass it if you manually call &lt;code&gt;submit()&lt;/code&gt;.
Angular v21.2 in fact updated the &lt;code&gt;submit()&lt;/code&gt; API to let you pass options as the second parameter
(&lt;code&gt;action&lt;/code&gt;, &lt;code&gt;onInvalid&lt;/code&gt;, &lt;code&gt;ignoreValidators&lt;/code&gt;) to override these defaults,
and the submit function now returns a &lt;code&gt;Promise&amp;lt;boolean&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;focus and &lt;code&gt;registerAsBinding&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;As explained in our &lt;a href=&quot;/2026/01/15/what-is-new-angular-21.1/&quot;&gt;previous blog post&lt;/a&gt;,
Angular v21.1 introduced the &lt;code&gt;focusBoundControl&lt;/code&gt; method on a field
to programmatically focus its form control in the DOM:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;protected readonly loginForm &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; form&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;credentials&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  submission&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    action&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;    onInvalid: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;      // 👇 automatically focus the first field with an error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;      const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; firstError&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;loginForm&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;errorSummary&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()[&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;      if&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;firstError&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;?.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;fieldTree&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;        firstError&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;fieldTree&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;focusBoundControl&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A typical &lt;code&gt;FormField&lt;/code&gt; will focus its host element (&lt;code&gt;input&lt;/code&gt;, &lt;code&gt;select&lt;/code&gt;, etc.) when &lt;code&gt;focusBoundControl&lt;/code&gt; is called.
For custom form controls that implements &lt;code&gt;FormValueControl&lt;/code&gt; or &lt;code&gt;FormCheckControl&lt;/code&gt;,
you&amp;#39;ll need to implement the &lt;code&gt;focus&lt;/code&gt; method to define how the control should be focused when &lt;code&gt;focusBoundControl&lt;/code&gt; is called:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; BirthYearInput&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; FormValueControl&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  focus&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    this.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;birthYearInput&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;nativeElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;focus&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But we can also have components or directives that don&amp;#39;t implement &lt;code&gt;FormValueControl&lt;/code&gt; or &lt;code&gt;FormCheckControl&lt;/code&gt;,
and instead receive the field as an input and bind it in the template.
In this case, we can use the new &lt;code&gt;registerAsBinding&lt;/code&gt; method to register the field as a binding,
which will make &lt;code&gt;focusBoundControl&lt;/code&gt; focus the chosen element:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; `&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [formField]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;formField()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; #button&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; (click)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;generate()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Generate&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;   `&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; Password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  readonly&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; formField&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;FieldTree&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  readonly&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; viewChild&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ElementRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;HTMLButtonElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  constructor&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // 👇 register the field as a binding, and specify to focus the button element&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    inject&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;FormField&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;registerAsBinding&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;      focus&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;nativeElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;focus&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the custom control is a directive,
the &lt;code&gt;registerAsBinding&lt;/code&gt; call can be done without specifying the &lt;code&gt;focus&lt;/code&gt; method,
as the directive host element will be focused by default:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Directive&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; PasswordDirective&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  readonly&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; formField&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;FieldTree&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  constructor&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // 👇 the directive host element will be focused by default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    inject&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;FormField&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;registerAsBinding&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: the &lt;code&gt;focus&lt;/code&gt; API now accepts and propagates &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus#options&quot;&gt;&lt;code&gt;FocusOptions&lt;/code&gt;&lt;/a&gt;
which allows control over focus behavior (for example, preventing scroll on focus with &lt;code&gt;{ preventScroll: true }&lt;/code&gt;).&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;transformedValue&lt;/code&gt; for custom controls&lt;/h3&gt;
&lt;p&gt;Another nice addition for custom controls is the new &lt;code&gt;transformedValue&lt;/code&gt; utility.
It helps synchronize a raw value entered by the user with the model value using &lt;code&gt;parse&lt;/code&gt; and &lt;code&gt;format&lt;/code&gt; functions,
while automatically reporting parse errors to the parent form.
The &lt;code&gt;parse&lt;/code&gt; function can either return an object with a &lt;code&gt;value&lt;/code&gt; property containing the parsed value,
or an object with an &lt;code&gt;errors&lt;/code&gt; property containing an array of errors if the value is invalid.
In this example, the user types a duration like &lt;code&gt;20m&lt;/code&gt; or &lt;code&gt;1h&lt;/code&gt;, and the form model stores the duration in minutes.
If the value is invalid, then a custom &lt;code&gt;parse&lt;/code&gt; error is reported to the form, which can be used to display an error message in the UI.
You can also return built-in validation errors from the &lt;code&gt;parse&lt;/code&gt; function,
for example to report that a negative duration is not allowed using a &lt;code&gt;min&lt;/code&gt; error.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  selector&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;duration-input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; `&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [value]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;rawValue()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; (input)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;onDurationInput($event)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; DurationInput&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; FormValueControl&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // model value exposed to the form (in minutes)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  readonly&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; model&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇 raw UI value (string) &amp;#x3C;-&gt; model value (minutes)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  readonly&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; rawValue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; transformedValue&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    parse&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;raw&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;      // normalize user input&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;      const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; raw&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;trim()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;toLowerCase()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;      if&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ===&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;      // `20m` -&gt; 20&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;      if&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;endsWith(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;m&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; minutes&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; Number(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;slice(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;isNaN(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;minutes&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; kind&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;parse&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; minutes&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; minError(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; minutes&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;      // `1h` -&gt; 60&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;      if&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;endsWith(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;h&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; hours&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; Number(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;slice(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;isNaN(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;hours&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; kind&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;parse&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; minutes&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; hours&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; minutes&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; minError(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; minutes&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;      // anything else is a parse error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;      return&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; kind&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;parse&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // format minutes back to a user-facing value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    format&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (value &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; `${&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;m&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  onDurationInput&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; Event&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;rawValue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; HTMLInputElement&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Nullable number inputs&lt;/h3&gt;
&lt;p&gt;Note that parse errors are now also integrated for native form inputs.
For example, if a user types an unparsable value in a &lt;code&gt;type=&amp;quot;number&amp;quot;&lt;/code&gt; input,
the model keeps its previous value and the field reports a &lt;code&gt;parse&lt;/code&gt; error.&lt;/p&gt;
&lt;p&gt;Signal Forms now better supports &lt;code&gt;null&lt;/code&gt; with native number inputs:
binding &lt;code&gt;null&lt;/code&gt; clears the input, and when users clear the field, the model becomes &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Our &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online workshop&lt;/a&gt; 
showcases a more complete example of &lt;code&gt;transformedValue&lt;/code&gt; usage in the &lt;code&gt;Signal Forms&lt;/code&gt; exercise 👀.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;SignalFormControl&lt;/code&gt; for incremental migration&lt;/h3&gt;
&lt;p&gt;Angular v21.2 also introduces &lt;code&gt;SignalFormControl&lt;/code&gt; in &lt;code&gt;@angular/forms/signals/compat&lt;/code&gt;.
It acts as a bridge between Signal Forms and classic Reactive Forms:
you can define signal-form validation rules, while still plugging this new control into a &lt;code&gt;FormGroup&lt;/code&gt; or &lt;code&gt;FormArray&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;protected readonly credentials &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;fb&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;group&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [Validators&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Validators&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;minLength&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)]]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇 use a SignalFormControl in a classic FormGroup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; SignalFormControl&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; p&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    required&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    minLength&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 6&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On the template side, you don&amp;#39;t need to do anything special to bind a &lt;code&gt;SignalFormControl&lt;/code&gt; with &lt;code&gt;formControlName&lt;/code&gt;/&lt;code&gt;formControl&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;@let&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; passwordCtrl &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;credentials&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;controls&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; formControlName&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (passwordCtrl&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;touched &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; passwordCtrl&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;hasError&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Password is required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It also exposes a &lt;code&gt;fieldTree&lt;/code&gt; so the control can be bound with &lt;code&gt;[formField]&lt;/code&gt; in templates.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;@let&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; passwordCtrl &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;credentials&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;controls&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;form-control&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [formField]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;passwordCtrl.fieldTree&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (passwordCtrl&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;touched &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; passwordCtrl&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;hasError&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;password-required-error&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;invalid-feedback&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Password is required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is particularly useful for bottom-up migration:
you can migrate one control at a time instead of rewriting the whole form in one pass.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SignalFormControl&lt;/code&gt; would not be really &amp;quot;signal-friendly&amp;quot; if it did not use a signal:
it in fact has a &lt;code&gt;sourceValue&lt;/code&gt; property which is a signal of the control value, and can be used:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;protected readonly passwordStrength &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; computed&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;passwordCtrl&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;sourceValue&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;SignalFormControl&lt;/code&gt; intentionally does not support some imperative &lt;code&gt;AbstractControl&lt;/code&gt; APIs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;disable()&lt;/code&gt; / &lt;code&gt;enable()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setValidators()&lt;/code&gt; / &lt;code&gt;addValidators()&lt;/code&gt; / &lt;code&gt;removeValidators()&lt;/code&gt; / &lt;code&gt;clearValidators()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setAsyncValidators()&lt;/code&gt; / &lt;code&gt;addAsyncValidators()&lt;/code&gt; / &lt;code&gt;removeAsyncValidators()&lt;/code&gt; / &lt;code&gt;clearAsyncValidators()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setErrors()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;markAsPending()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;State and validation are expected to be derived from signal rules instead.&lt;/p&gt;
&lt;h3&gt;Reactive &lt;code&gt;validateStandardSchema()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;validateStandardSchema()&lt;/code&gt; now supports signal-based schemas.
You can pass a function that returns the schema,
so validation can react to changing signals over time.
For example, if &lt;code&gt;minimumLength&lt;/code&gt; is a signal containing the minimum length,
you can now write: &lt;code&gt;validateStandardSchema(p, () =&amp;gt; z.object({ name: z.string().min(minimumLength()) }))&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Warning for rendered hidden fields&lt;/h3&gt;
&lt;p&gt;Angular now warns in dev mode when a field marked as hidden is still rendered in the DOM.
In Signal Forms, hidden fields should be guarded in the template (typically with &lt;code&gt;@if&lt;/code&gt;),
so this warning helps catch accidental rendering of hidden controls:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;NG01916:&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; Field&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; is&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; hidden&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; but&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; is&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; being&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; rendered.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;Hidden&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; fields&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; should&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; be&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; removed&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; the&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; DOM&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; using&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; @if.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Animations&lt;/h2&gt;
&lt;p&gt;It is now possible to have nested animations,
where a component with its own animations is used inside another component that also has animations.
Previously, only the animations of the top-level component were working when components were destroyed,
but with this change, animations defined in nested components will be properly triggered first.&lt;/p&gt;
&lt;h2&gt;Router&lt;/h2&gt;
&lt;p&gt;Angular now lets you configure trailing slash behavior through dedicated location strategies.
You can choose to always write URLs with a trailing slash,
or to always remove it:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;bootstrapApplication&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(AppComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  providers&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // 👇 always write URLs with a trailing slash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; provide&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; LocationStrategy&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; useClass&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; TrailingSlashPathLocationStrategy &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // or never&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // { provide: LocationStrategy, useClass: NoTrailingSlashPathLocationStrategy }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;canMatch&lt;/code&gt; now gets a partial route snapshot&lt;/h3&gt;
&lt;p&gt;Another useful router change is that &lt;code&gt;canMatch&lt;/code&gt; now receives a third argument:
a partial route snapshot (&lt;code&gt;PartialMatchRouteSnapshot&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;This addresses a long-standing limitation where &lt;code&gt;canMatch&lt;/code&gt; had access to &lt;code&gt;route&lt;/code&gt; and &lt;code&gt;segments&lt;/code&gt;,
but not to params like &lt;code&gt;{ userId: &amp;#39;123&amp;#39; }&lt;/code&gt;.
With this snapshot argument, the guard can directly read &lt;code&gt;params&lt;/code&gt;, &lt;code&gt;queryParams&lt;/code&gt;, &lt;code&gt;fragment&lt;/code&gt;, etc.&lt;/p&gt;
&lt;h2&gt;DevTools&lt;/h2&gt;
&lt;p&gt;Angular DevTools now visualizes &lt;code&gt;resource()&lt;/code&gt; relationships in dedicated clusters in the signal graph.
DevTools also adds dependency-path highlighting from the node details panel.
You can now highlight:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;upstream dependencies (what this node depends on)&lt;/li&gt;
&lt;li&gt;downstream dependents (what depends on this node)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This can be helpful when debugging update propagation in large signal graphs.&lt;/p&gt;
&lt;h2&gt;Angular CLI&lt;/h2&gt;
&lt;h3&gt;Unit tests&lt;/h3&gt;
&lt;p&gt;The CLI now supports &lt;code&gt;ng add&lt;/code&gt; for Vitest browser providers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@vitest/browser-playwright&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@vitest/browser-webdriverio&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@vitest/browser-preview&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When used on a project already configured with the &lt;code&gt;@angular/build:unit-test&lt;/code&gt; builder (and Vitest runner),
the schematic installs the selected provider package
plus required peer dependencies (like &lt;code&gt;playwright&lt;/code&gt; or &lt;code&gt;webdriverio&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;So you can now run:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ng&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; @vitest/browser-playwright&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The unit-test builder has a new &lt;code&gt;headless&lt;/code&gt; option to force all configured browsers to run headless:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;builder&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;@angular/build:unit-test&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;browsers&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Chromium&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;headless&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is an alternative to the hard-coded convention used until now,
where you had to name the browser with a &lt;code&gt;Headless&lt;/code&gt; suffix to run it headlessly (for example &lt;code&gt;ChromiumHeadless&lt;/code&gt;).&lt;/p&gt;
&lt;h3&gt;Prettier&lt;/h3&gt;
&lt;p&gt;The CLI now has built-in Prettier integration!&lt;/p&gt;
&lt;p&gt;New generated applications now include a &lt;code&gt;.prettierrc&lt;/code&gt; file,
with &lt;code&gt;prettier&lt;/code&gt; a dev dependency.
Files created/modified by schematics are automatically formatted when possible
and &lt;code&gt;ng update&lt;/code&gt; migrations now also run formatting on changed files.&lt;/p&gt;
&lt;p&gt;This reduces formatting noise after &lt;code&gt;ng generate&lt;/code&gt; and &lt;code&gt;ng update&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;This was a packed release for a minor version.
Arrow functions and exhaustive &lt;code&gt;@switch&lt;/code&gt; type-checking on the template side,
the &lt;code&gt;ChangeDetectionStrategy.Eager&lt;/code&gt; alias as the OnPush as default migration is coming,
and a wave of Signal Forms improvements: &lt;code&gt;FormRoot&lt;/code&gt;, &lt;code&gt;transformedValue&lt;/code&gt;, &lt;code&gt;SignalFormControl&lt;/code&gt; for incremental migration.
Next version should be the v22 release.&lt;/p&gt;
&lt;p&gt;Stay tuned!&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>What&apos;s new in Angular 21.1?</title>
    <link href="https://blog.ninja-squad.com/2026/01/15/what-is-new-angular-21.1"/>
    <updated>2026-01-15T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2026/01/15/what-is-new-angular-21.1</id>
    <content type="html">
      &lt;p&gt;Angular&amp;nbsp;21.1.0 is here!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;a href=&quot;https://github.com/angular/angular/releases/tag/v21.1.0&quot;&gt;
    &lt;img class=&quot;img-fluid&quot; style=&quot;max-width: 60%;&quot; src=&quot;/assets/images/angular_gradient.webp&quot; alt=&quot;Angular logo&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Two months after the huge v21 release,
the Angular team delivers a new minor update.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s dive in!&lt;/p&gt;
&lt;h2&gt;Signal Forms&lt;/h2&gt;
&lt;p&gt;A meaningful change in Signal Forms is the renaming of the &lt;code&gt;[field]&lt;/code&gt; directive to &lt;code&gt;[formField]&lt;/code&gt;.
The &lt;code&gt;[field]&lt;/code&gt; selector was too generic and likely to cause naming collisions with existing components.
Therefore, the Angular team decided to rename both the directive class (from &lt;code&gt;Field&lt;/code&gt; to &lt;code&gt;FormField&lt;/code&gt;)
and the directive selector (from &lt;code&gt;[field]&lt;/code&gt; to &lt;code&gt;[formField]&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;You should now use &lt;code&gt;[formField]&lt;/code&gt; instead of &lt;code&gt;[field]&lt;/code&gt; to bind form controls:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [formField]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;form.name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Field&lt;/code&gt; directive has been removed,
so you&amp;#39;ll have some renaming to do if you already use experimental Signal Forms.&lt;/p&gt;
&lt;p&gt;Another name change in Signal Forms is the renaming of the &lt;code&gt;field&lt;/code&gt; property to &lt;code&gt;fieldTree&lt;/code&gt;
in validation error interfaces and field contexts.
If you&amp;#39;re writing custom validators,
you&amp;#39;ll need to update your code to use &lt;code&gt;fieldTree&lt;/code&gt; instead of &lt;code&gt;field&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// Before&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ValidationError&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇 targets the password field&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  field&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; context&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;fieldTree&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  kind&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;password-different-from-email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Password should not be the same as email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// After v21.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ValidationError&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇 targets the password field&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  fieldTree&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; context&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;fieldTree&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  kind&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;password-different-from-email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Password should not be the same as email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This change affects the &lt;code&gt;ValidationError&lt;/code&gt; interface and the &lt;code&gt;FieldContext&lt;/code&gt; interface.&lt;/p&gt;
&lt;p&gt;Signal Forms gained a new feature in v21.1:
the ability to automatically apply CSS classes to fields based on their state 🚀.&lt;/p&gt;
&lt;p&gt;One of the missing features of signal forms compared to the classic reactive/template-driven forms
was the automatic CSS classes that were added to form controls
(&lt;code&gt;ng-valid&lt;/code&gt;, &lt;code&gt;ng-dirty&lt;/code&gt;, &lt;code&gt;ng-touched&lt;/code&gt;, etc.).&lt;/p&gt;
&lt;p&gt;This is now possible using the &lt;code&gt;provideSignalFormsConfig()&lt;/code&gt; function
in your application configuration:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;provideSignalFormsConfig&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  classes&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;is-invalid&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; field&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; field&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;invalid&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; field&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;touched&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, the &lt;code&gt;is-invalid&lt;/code&gt; CSS class will be automatically added
to any field that is invalid and touched.
You can define as many classes as you want,
and use any property of the &lt;code&gt;Field&lt;/code&gt;/&lt;code&gt;FormField&lt;/code&gt; directive,
like its state (&lt;code&gt;invalid()&lt;/code&gt;, &lt;code&gt;touched()&lt;/code&gt;, &lt;code&gt;dirty()&lt;/code&gt;, etc.)
or its host element (a new property added in this version)
to determine when the class should be applied.&lt;/p&gt;
&lt;p&gt;This makes it easier to style your forms,
especially when using CSS frameworks like Bootstrap or Tailwind
that rely on specific CSS classes to style form inputs.&lt;/p&gt;
&lt;p&gt;Note that you can have the &amp;quot;old&amp;quot; behavior with &lt;code&gt;ng-valid&lt;/code&gt;/&lt;code&gt;ng-invalid&lt;/code&gt;/&lt;code&gt;ng-dirty&lt;/code&gt;/&lt;code&gt;ng-touched&lt;/code&gt;... classes
by using:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;provideSignalFormsConfig&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  classes&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; NG_STATUS_CLASSES&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Signal Forms now also support custom control directives!
Previously, the &lt;code&gt;[field]&lt;/code&gt; binding could only be used with components.
Now, you can create directives that implement the &lt;code&gt;FormValueControl&lt;/code&gt; or &lt;code&gt;FormCheckboxControl&lt;/code&gt; interfaces
and bind them with &lt;code&gt;[formField]&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [formField]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;form.name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; appCustomControl&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Signal Forms also gained a new &lt;code&gt;focusBoundControl()&lt;/code&gt;
method on the field state.
This is particularly useful for accessibility
or when you want to focus a specific field after a validation error.&lt;/p&gt;
&lt;p&gt;This allows you to programmatically focus the input element
associated with a form field,
for example when a submission failed:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;protected async &lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;register&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(event: SubmitEvent) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  event&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;preventDefault&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  await&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; submit&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;userForm&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; form&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇 automatically focus the first field with an error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; firstError&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;userForm&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;errorSummary&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()[&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;firstError&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;?.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;fieldTree&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;    firstError&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;fieldTree&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;focusBoundControl&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will automatically focus the first input/select/textarea
associated with a field that has an error,
but the cool thing is that it can also work with custom control components!
You just have to implement a &lt;code&gt;focus()&lt;/code&gt; method in your custom control,
and &lt;code&gt;focusBoundControl()&lt;/code&gt; will automatically call it:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; BirthYearInput&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; FormValueControl&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  focus&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    this.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;birthYearInput&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;nativeElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;focus&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;NOTE: We added a Signal Forms exercise to our online workshop,
&lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;check it out&lt;/a&gt;!&lt;/p&gt;
&lt;h2&gt;Control flow&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;@switch&lt;/code&gt; control flow now supports multiple consecutive &lt;code&gt;@case&lt;/code&gt; blocks matching a single content block.&lt;/p&gt;
&lt;p&gt;Previously, each &lt;code&gt;@case&lt;/code&gt; required its own content.
Now you can specify multiple conditions for a single block,
similar to fall-through behavior in traditional switch statements:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@switch&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (status) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  @case&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;draft&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  @case&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;pending&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Your document is not yet published&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  @case&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;published&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Your document is live&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  @default&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Unknown status&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, both &amp;#39;draft&amp;#39; and &amp;#39;pending&amp;#39; statuses will display the same message,
making the code more concise when multiple conditions should produce the same result.&lt;/p&gt;
&lt;h2&gt;Template spread operator&lt;/h2&gt;
&lt;p&gt;Angular templates now support the spread operator (&lt;code&gt;...&lt;/code&gt;)!
This allows you to spread an object into an object
or an array into another array:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;@let&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; users &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;[currentUser&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;admins]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It also supports the spread syntax in function calls.
This is particularly useful for functions that use rest parameters,
a syntax that allows a function to accept an indefinite number of arguments as an array:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; (click)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;sum(...counters)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Sum all&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Spoiler for the next version: 
we will get arrow function support in templates in v21.2!&lt;/p&gt;
&lt;h2&gt;Router&lt;/h2&gt;
&lt;p&gt;The router introduces a new standalone &lt;code&gt;isActive()&lt;/code&gt; function that returns a computed signal
indicating whether a given URL is currently active.&lt;/p&gt;
&lt;p&gt;This new function is a more tree-shakeable alternative to the existing &lt;code&gt;Router.isActive()&lt;/code&gt; method,
which is now deprecated in v21.1:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; isActive&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;@angular/router&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; active &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; isActive&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;/home&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;router&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; paths&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;exact&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; queryParams&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;exact&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; fragment&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ignored&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; matrixParams&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ignored&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The function returns a signal that automatically updates when the router state changes,
making it easier to reactively track active routes.&lt;/p&gt;
&lt;p&gt;The router also gained better memory management capabilities in v21.1
if you use a custom &lt;code&gt;RouteReuseStrategy&lt;/code&gt; implementation
(which is not that common).&lt;/p&gt;
&lt;p&gt;A new experimental feature &lt;code&gt;withExperimentalAutoCleanupInjectors()&lt;/code&gt; automatically destroys
unused route injectors after navigation,
helping to prevent memory leaks in applications with many routes or long-lived sessions.&lt;/p&gt;
&lt;p&gt;You can enable it when configuring your routes:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;provideRouter&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(routes&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; withExperimentalAutoCleanupInjectors&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;())&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Additionally, a new &lt;code&gt;destroyDetachedRouteHandle()&lt;/code&gt; function is available
for manually cleaning up detached route handles in custom &lt;code&gt;RouteReuseStrategy&lt;/code&gt; implementations.&lt;/p&gt;
&lt;p&gt;Finally, the router introduces an experimental integration with the browser&amp;#39;s &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Navigation_API&quot;&gt;Navigation API&lt;/a&gt;.
This API is a modern alternative to the traditional History API, providing a more robust way to handle navigations.&lt;/p&gt;
&lt;p&gt;By enabling this experimental feature, the Angular router can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;intercept navigations triggered outside the router and convert them to SPA navigations.&lt;/li&gt;
&lt;li&gt;leverage native browser scroll and focus restoration.&lt;/li&gt;
&lt;li&gt;communicate ongoing navigations to the browser for better accessibility
and user experience (native loading progress, stop button, etc.).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can enable it using the &lt;code&gt;withExperimentalPlatformNavigation()&lt;/code&gt; feature:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;provideRouter&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(routes&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; withExperimentalPlatformNavigation&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;())&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This feature is &lt;strong&gt;highly experimental&lt;/strong&gt;
and the native browser support is currently very limited.
This won&amp;#39;t be stabilized until the Navigation API is more widely supported.
When this is done, it may not become a router feature (&lt;code&gt;with...&lt;/code&gt;)
but rather a different router provider,
which would allow to tree-shake the current history-based classes.&lt;/p&gt;
&lt;h2&gt;Debugging stability&lt;/h2&gt;
&lt;p&gt;A new debugging utility &lt;code&gt;provideStabilityDebugging()&lt;/code&gt; helps developers troubleshoot applications
that fail to stabilize during hydration.&lt;/p&gt;
&lt;p&gt;If your application doesn&amp;#39;t reach a stable state within 9 seconds,
this utility logs diagnostic information to the console,
including pending tasks and their stack traces.
This is particularly useful when debugging hydration timeouts in SSR applications.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; provideStabilityDebugging&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;@angular/core&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;bootstrapApplication&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(AppComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  providers&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;provideStabilityDebugging&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that this utility is provided by default in dev mode when using &lt;code&gt;provideClientHydration()&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Vitest&lt;/h2&gt;
&lt;p&gt;The Angular CLI&amp;#39;s migration schematic for converting Jasmine tests to Vitest
now supports a &lt;code&gt;browserMode&lt;/code&gt; option (a contribution from my fellow ninja JB!).&lt;/p&gt;
&lt;p&gt;If you&amp;#39;re migrating your tests to Vitest and plan to use Vitest&amp;#39;s browser mode
(you should, read our blog post about &lt;a href=&quot;/2025/11/18/angular-tests-with-vitest-browser-mode&quot;&gt;Vitest browser mode&lt;/a&gt;),
you can now use this option to preserve certain assertions
that are natively supported in browser mode:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ng&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; generate&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; refactor-jasmine-vitest&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; --browser-mode&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When this option is enabled,
the migration will keep the &lt;code&gt;toHaveClass&lt;/code&gt; matcher in its original form
instead of converting it to a different assertion,
since Vitest&amp;#39;s browser mode provides its own &lt;code&gt;toHaveClass&lt;/code&gt; matcher.&lt;/p&gt;
&lt;p&gt;This makes the migration smoother for projects that want to run their tests
in a real browser environment,
ensuring your tests work as expected without manual adjustments after the migration.&lt;/p&gt;
&lt;p&gt;The schematic also now generates a detailed migration report by default,
creating a markdown file that lists all the TODOs and manual tasks
that need to be addressed after the automatic migration.
This report includes precise file paths and line numbers,
making it easier to quickly identify and fix any remaining migration tasks in large codebases.
You can disable this with &lt;code&gt;--no-report&lt;/code&gt; if you don&amp;#39;t need it.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;Jasmine to Vitest Refactoring Report&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Date: 2025-12-17T15:16:43.108Z&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;## &lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;Summary&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;                   |&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Count &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|:------------------|------:|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Files Scanned     &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;   159 &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Files Transformed &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;   151 &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Files Skipped     &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;     8 &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Total TODOs       &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;     3 &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;## &lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;TODO Overview&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Category    &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Count &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|:------------|------:|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; addMatchers &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;     3 &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;## &lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;Files Requiring Manual Attention&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;AI&lt;/h2&gt;
&lt;p&gt;The MCP server gained a few new (experimental) tools that enable AI assistants
to control Angular projects more effectively:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;build&lt;/code&gt;: compiles the Angular application&lt;/li&gt;
&lt;li&gt;&lt;code&gt;devserver.start&lt;/code&gt;: launches the development server&lt;/li&gt;
&lt;li&gt;&lt;code&gt;devserver.stop&lt;/code&gt;: terminates the running development server&lt;/li&gt;
&lt;li&gt;&lt;code&gt;devserver.wait_for_build&lt;/code&gt;: waits until the dev server completes its build process&lt;/li&gt;
&lt;li&gt;&lt;code&gt;test&lt;/code&gt;: runs unit tests via &lt;code&gt;ng test&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;e2e&lt;/code&gt;: runs end-to-end tests via &lt;code&gt;ng e2e&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These tools allow AI assistants like Claude to programmatically build your application,
manage the development server, and run your tests,
making it easier to verify that everything compiles correctly and all tests pass.&lt;/p&gt;
&lt;p&gt;You can now enable all experimental tools at once using the &lt;code&gt;all&lt;/code&gt; group in your MCP configuration,
making it easier to get started with the full suite of AI assistance features:
&lt;code&gt;ng mcp --experimental-tool=all&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The already existing &lt;code&gt;ai_tutor&lt;/code&gt; tool continues to evolve.
A new lesson has been added to the interactive learning experience: Signal Forms!&lt;/p&gt;
&lt;p&gt;If you&amp;#39;re curious about Signal Forms,
the AI tutor can be a nice resource,
but you should definitely check out our
2 &lt;a href=&quot;/2025/11/04/angular-signal-forms-part-1&quot;&gt;part&lt;/a&gt; &lt;a href=&quot;/2025/11/14/angular-signal-forms-part-2&quot;&gt;series&lt;/a&gt;
on Signal Forms if you haven&amp;#39;t already 😉&lt;/p&gt;
&lt;p&gt;The Angular team continues to improve the infrastructure for AI assistance.
Code examples are now embedded directly in Angular packages (starting with &lt;code&gt;@angular/forms&lt;/code&gt;)
using a SQLite database,
making them easily accessible to the MCP server and other tooling.
This builds upon the code examples feature introduced in earlier versions,
improving the AI&amp;#39;s ability to provide contextual code snippets and guidance,
and we&amp;#39;ll probably see more code examples added in future releases in the various packages.&lt;/p&gt;
&lt;p&gt;Finally, setting up the MCP server is now easier than ever.
New Angular workspaces now include a &lt;code&gt;.vscode/mcp.json.template&lt;/code&gt; file
with a pre-configured setup for the Angular CLI MCP server.
This eliminates the need for manual configuration
and makes it straightforward to start using AI assistance in your Angular projects.
You can learn more about this on the &lt;a href=&quot;https://angular.dev/ai/mcp&quot;&gt;Angular MCP documentation page&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;That&amp;#39;s all for this release!
Signal Forms continue to improve with CSS class configuration, custom control directives support,
the &lt;code&gt;focusBoundControl()&lt;/code&gt; method, and naming improvements.
The router gained an experimental integration with the Navigation API.
The CLI team focused on AI features and the Vitest stabilization.&lt;/p&gt;
&lt;p&gt;Stay tuned!&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>What&apos;s new in Angular 21.0?</title>
    <link href="https://blog.ninja-squad.com/2025/11/20/what-is-new-angular-21.0"/>
    <updated>2025-11-20T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2025/11/20/what-is-new-angular-21.0</id>
    <content type="html">
      &lt;p&gt;Angular&amp;nbsp;21.0.0 is here!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;a href=&quot;https://github.com/angular/angular/releases/tag/21.0.0&quot;&gt;
    &lt;img class=&quot;img-fluid&quot; style=&quot;max-width: 60%&quot; src=&quot;/assets/images/angular_gradient.webp&quot; alt=&quot;Angular logo&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;The highlights? &lt;strong&gt;Signal Forms&lt;/strong&gt; and &lt;strong&gt;zoneless change detection by default&lt;/strong&gt;.
The CLI, with Vitest becoming the default testing framework, 
also delivers on a long due improvement.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s dive in!&lt;/p&gt;
&lt;h2&gt;Signal Forms (experimental)&lt;/h2&gt;
&lt;p&gt;Angular 21 introduces a new experimental way to build forms: &lt;strong&gt;Signal Forms&lt;/strong&gt;,
in the &lt;code&gt;@angular/forms/signals&lt;/code&gt; package.
This signal-based approach provides better type safety and easier validation
compared to traditional reactive and template-driven forms.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;private readonly credentials &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; signal&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;protected readonly loginForm &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; form&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;credentials&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇 add validators to the fields, with their error messages&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;  form&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // email is mandatory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    required&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Email is required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // must be a valid email&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    email&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Email is not valid&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // password is mandatory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    required&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Password is required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // should have at least 6 characters&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    minLength&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 6&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;      // can also be a function, if you need to access the current value/state of the field&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;      message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; password&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; `&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Password should have at least 6 characters but has only &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We wrote a two-part series to introduce you all the concepts of Signal Forms.
The first one covers the basics, while the second one dives into more advanced topics
like custom validation, custom form components, etc.&lt;/p&gt;
&lt;p&gt;Check them out!&lt;/p&gt;
&lt;p&gt;👉 &lt;a href=&quot;/2025/11/04/angular-signal-forms-part-1/&quot;&gt;Angular Signal Forms - Part 1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;👉 &lt;a href=&quot;/2025/11/14/angular-signal-forms-part-2/&quot;&gt;Angular Signal Forms - Part 2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There is also an effort to make the migration to signal forms more progressive,
with the introduction of the &lt;code&gt;@angular/forms/signals/compat&lt;/code&gt; package.
This package offers a &lt;code&gt;compatForm&lt;/code&gt; function,
which is a version of the &lt;code&gt;form&lt;/code&gt; function designed for backwards
compatibility with reactive forms by accepting reactive controls as a part of the data.
I&amp;#39;m not sure that this will save us from completely rewriting our forms,
but we appreciate the effort 🫡.&lt;/p&gt;
&lt;h2&gt;Zoneless by default 🚀&lt;/h2&gt;
&lt;p&gt;Angular applications are now zoneless by default!
&lt;code&gt;provideZonelessChangeDetection()&lt;/code&gt; is no longer needed in new applications,
as Angular will use zoneless change detection automatically.
If your application relies on Zone.js,
you will need to explicitly add &lt;code&gt;provideZoneChangeDetection()&lt;/code&gt; in the root providers.
A migration will automatically add it for you if necessary when updating to Angular v21.&lt;/p&gt;
&lt;p&gt;The CLI now generates zoneless applications by default,
and you&amp;#39;ll note that the component tests use &lt;code&gt;await fixture.whenStable()&lt;/code&gt;
instead of &lt;code&gt;fixture.detectChanges()&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Core&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;SimpleChanges&lt;/code&gt; type that we use for the &lt;code&gt;ngOnChanges&lt;/code&gt; parameter is now generic
and can be type safe, if you add the type of your component as a type parameter.
To keep the backward compatibility,
it defaults to &lt;code&gt;any&lt;/code&gt; when no type parameter is provided.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; User&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; OnChanges&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  readonly&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇 ngOnChanges is now type safe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  ngOnChanges&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;changes&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; SimpleChanges&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;):&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; nameChange&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; changes&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // typed as `SimpleChange&amp;#x3C;string&gt; | undefined`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;nameChange&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;      console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Name changed from &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;nameChange&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;previousValue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;nameChange&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;currentValue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Forms&lt;/h2&gt;
&lt;p&gt;In &amp;quot;classic&amp;quot; forms,
a new &lt;code&gt;FormArrayDirective&lt;/code&gt; directive has been added,
allowing to have an array as the top element of a form.
Until now, you had to wrap it in a &lt;code&gt;FormGroup&lt;/code&gt; and use the &lt;code&gt;FormGroupDirective&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Http&lt;/h2&gt;
&lt;p&gt;The big change is that &lt;code&gt;HttpClient&lt;/code&gt; is now provided in the root injector by default.
We no longer need to use &lt;code&gt;provideHttpClient()&lt;/code&gt; in our applications,
except when we want to customize the HTTP client
(for example, to register interceptors).
It also simplifies the testing setup, where it was a bit verbose to have to use both 
&lt;code&gt;provideHttpClient()&lt;/code&gt; and &lt;code&gt;provideHttpClientTesting()&lt;/code&gt;.
We can now only use the latter.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;HttpClient&lt;/code&gt; also gained a few options in its Fetch version:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;responseType&lt;/code&gt; has been added
(corresponding to the response &lt;code&gt;type&lt;/code&gt; property in the native fetch API, see the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Response/type&quot;&gt;MDN docs&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;referrerPolicy&lt;/code&gt; which can be used to specify the referrer information
(see the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Referrer-Policy&quot;&gt;MDN docs&lt;/a&gt;)
has been added to the client and in the &lt;code&gt;HttpResource&lt;/code&gt; options.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Router&lt;/h2&gt;
&lt;p&gt;The router gained a new &lt;code&gt;scroll&lt;/code&gt; option that can be used when navigating
to define the scrolling behaviour 
(allowing to override the scroll restoration behaviour
that you can enable in &lt;code&gt;provideRouter&lt;/code&gt; thanks to &lt;code&gt;withInMemoryScrolling({ scrollPositionRestoration: &amp;#39;enabled&amp;#39; })&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;scroll&lt;/code&gt; option can be &lt;code&gt;&amp;#39;manual&amp;#39;&lt;/code&gt; (no scrolling even if enabled globally)
or &lt;code&gt;&amp;#39;after-transition&amp;#39;&lt;/code&gt; (following the global behaviour).
So, using &lt;code&gt;router.navigateByUrl(&amp;#39;/&amp;#39;, { scroll: &amp;#39;manual&amp;#39; })&lt;/code&gt; will prevent scrolling
even if scroll restoration is enabled globally.&lt;/p&gt;
&lt;h2&gt;Templates&lt;/h2&gt;
&lt;p&gt;The control flow migration will automatically be applied
when updating to Angular v21,
if you did not apply it yet.&lt;/p&gt;
&lt;p&gt;Since the updated style guide written for 
&lt;a href=&quot;/2025/05/28/what-is-new-angular-20.0/&quot;&gt;Angular v20&lt;/a&gt;,
it is now recommended to use &lt;code&gt;class&lt;/code&gt; and &lt;code&gt;style&lt;/code&gt; bindings
instead of the &lt;code&gt;NgClass&lt;/code&gt; and &lt;code&gt;NgStyle&lt;/code&gt; directives. &lt;/p&gt;
&lt;p&gt;Angular v21 offers automatic migrations (optional) to help you with this change!&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ng&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; g&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; @angular/core:ngclass-to-class-migration&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ng&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; g&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; @angular/core:ngstyle-to-style-migration&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another optional migration has been added to migrate &lt;code&gt;CommonModule&lt;/code&gt; imports
to the individual directives/pipes standalone imports:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ng&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; g&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; @angular/core:common-to-standalone&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Speaking of changes in the templates,
RegExp are now supported:
you can now write something like &lt;code&gt;&amp;lt;div&amp;gt;{{ /\\d+/.test(id()) }}&amp;lt;/div&amp;gt;&lt;/code&gt; in your HTML files.
I&amp;#39;m not sure why anyone would want to do that, but well...&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;@defer&lt;/code&gt; trigger &lt;code&gt;on viewport&lt;/code&gt; also gained a new option,
allowing to define the options of the underlying
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API&quot;&gt;&lt;code&gt;IntersectionObserver&lt;/code&gt;&lt;/a&gt;.
You can now write a &lt;code&gt;@defer&lt;/code&gt; like this:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@defer&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (on &lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;viewport&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;({ trigger&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; rootMargin: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;50px&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; })) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Compiler&lt;/h2&gt;
&lt;p&gt;In v21, the compiler now has its &lt;code&gt;typeCheckHostBindings&lt;/code&gt; option enabled by default
(see our &lt;a href=&quot;/2025/05/28/what-is-new-angular-20.0&quot;&gt;blog post about v20&lt;/a&gt; to learn more about what it does).&lt;/p&gt;
&lt;p&gt;A new diagnostic has also been added to detect when a component
reads a required input/model/viewChild/contentChild property
before it is initialized.
This was already throwing an error at runtime,
but now you will get a compile-time error instead.&lt;/p&gt;
&lt;p&gt;Another diagnostic has been added to detect unreachable or duplicated or inefficient &lt;code&gt;@defer&lt;/code&gt; triggers.&lt;/p&gt;
&lt;h2&gt;Styles encapsulation&lt;/h2&gt;
&lt;p&gt;A new strategy for view encapsulation has been added: &lt;code&gt;ExperimentalIsolatedShadowDom&lt;/code&gt;.
As its name indicates, it is still experimental.
It leverages Shadow DOM to provide true encapsulation of styles,
but also isolates the component from the rest of the application.
Unlike &lt;code&gt;ShadowDom&lt;/code&gt; encapsulation,
it prevents styles from leaking in or out of the component.
This is useful when you want to ensure that the component&amp;#39;s styles
are completely isolated from the rest of the application,
including global styles.
There are still some issues with the implementation,
so it is not recommended for production use yet.&lt;/p&gt;
&lt;h2&gt;Vitest is the new default&lt;/h2&gt;
&lt;p&gt;Big change in the unit testing setup:
Vitest is now the default testing framework when creating new applications
with the CLI! 😲&lt;/p&gt;
&lt;p&gt;Karma/Jasmine has been the default for a long time,
even though Karma has been deprecated for a while.
The experimental &lt;code&gt;@angular/build:unit-test&lt;/code&gt; is now stable
and uses Vitest by default.
Some efforts have been made to simplify the configuration as much as possible,
and the minimal setup in &lt;code&gt;angular.json&lt;/code&gt; is now:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;builder&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;@angular/build:unit-test&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see the difference in a generated project
on &lt;a href=&quot;https://github.com/cexbrayat/angular-cli-diff/compare/20.0.0...21.0.0&quot;&gt;angular-cli-diff&lt;/a&gt;.
This little project that we maintain proves to be really useful
to see what changed between CLI versions when you want to update your projects.&lt;/p&gt;
&lt;p&gt;Even if the configuration is simpler, you can still customize it a lot with the following options,
either in &lt;code&gt;angular.json&lt;/code&gt; or via CLI options when running &lt;code&gt;ng test&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;coverage&lt;/code&gt; (and all coverage related options, like &lt;code&gt;coverageInclude&lt;/code&gt;, &lt;code&gt;coverageExclude&lt;/code&gt;, &lt;code&gt;coverageThresholds&lt;/code&gt;, etc.) to configure code coverage&lt;/li&gt;
&lt;li&gt;&lt;code&gt;browsers&lt;/code&gt; to define which browsers to use for testing. Note that Vitest stabilized the Browser Mode in v4, so you can now run tests in real browsers instead of jsdom/happy-dom if you want to. The &lt;code&gt;browserViewport&lt;/code&gt; option allows to define the viewport size for browser tests.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reporters&lt;/code&gt; to define which reporters to use, and &lt;code&gt;output-file&lt;/code&gt; to define where to output the report.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setupFiles&lt;/code&gt; to define setup files to be run before the tests and &lt;code&gt;providersFile&lt;/code&gt; to define a file that provides Angular testing providers.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ui&lt;/code&gt; if you want to use Vitest&amp;#39;s UI mode.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;watch&lt;/code&gt; to enable/disable watch mode (true by default when running &lt;code&gt;ng test&lt;/code&gt;, but false in CI environments).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;filter&lt;/code&gt; to run only tests matching a specific pattern in their test suite or test name.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;list-tests&lt;/code&gt; to list all the tests without running them (useful to check what the &lt;code&gt;include&lt;/code&gt;/&lt;code&gt;exclude&lt;/code&gt; options are doing).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The CLI team also added a &lt;code&gt;runnerConfig&lt;/code&gt; option
to allow using a custom Vitest configuration file,
if you need to customize something not covered by the CLI options.
For example, if you want to enable Vitest isolation mode (disabled by default in the CLI as it slows down tests),
you can add a &lt;code&gt;vitest-base.config.ts&lt;/code&gt; file to your project using: &lt;code&gt;ng g config vitest&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then customize it like this:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; defineConfig&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;vitest/config&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; defineConfig&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  test&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    isolate&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We really like Vitest and its Browser Mode that allows to use real browsers
and write more expressive tests using its &lt;code&gt;Locator&lt;/code&gt; API.
We wrote a dedicated blog post to explain how to
write more expressive than ever component unit tests 🤩:&lt;/p&gt;
&lt;p&gt;👉 &lt;a href=&quot;/2025/11/18/angular-tests-with-vitest-browser-mode/&quot;&gt;Angular tests with Vitest browser mode&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It is still possible to use Karma if you want to,
by setting the &lt;code&gt;runner&lt;/code&gt; option to &lt;code&gt;&amp;quot;karma&amp;quot;&lt;/code&gt;.
And you can generate a new project with Karma as the default
by using &lt;code&gt;ng new my-app --test-runner=karma&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A migration is also available to migrate existing tests from Jasmine to Vitest:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ng&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; generate&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; refactor-jasmine-vitest&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This migration is fairly mechanical,
so you&amp;#39;ll probably have to manually adjust some tests afterward.
But it should save you some time,
as it replaces all Jasmine-specific functions, types, matchers and imports with their Vitest equivalents!
It does not migrate the test setup or dependencies though,
so you&amp;#39;ll have to do that part manually.&lt;/p&gt;
&lt;p&gt;The migration has some useful options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--add-imports&lt;/code&gt; to automatically add the Vitest imports in your test files (if you don&amp;#39;t want to use global imports, which is the default when generating a new application)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--file-suffix&lt;/code&gt; if you use a different suffix than &lt;code&gt;.spec.ts&lt;/code&gt; for your test files&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--include&lt;/code&gt; to target only specific files or folders&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that &lt;code&gt;fakeAsync&lt;/code&gt; tests need to be rewritten,
as &lt;code&gt;fakeAsync&lt;/code&gt; relies on a patched Zone.js for Jasmine,
and there is no version of it for Vitest.
The migration will also add helpful TODO comments in your tests
to indicate where it couldn&amp;#39;t automatically migrate them.&lt;/p&gt;
&lt;p&gt;Vitest is definitely a great addition to Angular,
and the way to go if you start a new project!
The &lt;code&gt;web-test-runner&lt;/code&gt; and &lt;code&gt;jest&lt;/code&gt; experimental builders
which were introduced as a possible alternative to Vitest
will be removed in v22.&lt;/p&gt;
&lt;h2&gt;ng serve&lt;/h2&gt;
&lt;p&gt;It is now possible to define variables that will be replaced
during the serve process,
using the &lt;code&gt;define&lt;/code&gt; option in the serve configuration.
For example, you can define a &lt;code&gt;VERSION&lt;/code&gt; variable
that will be replaced with the version of your application
from the command line (making it simple to use environment variables):&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ng&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; serve&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; --define&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; VERSION=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;&apos;1.0.0&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then use it in your code:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// @ts-expect-error defined with --define flag&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;App version: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;VERSION&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This was already possible since v17.2 in builds,
but is now also available for &lt;code&gt;ng serve&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Tailwind schematic&lt;/h2&gt;
&lt;p&gt;A new schematic has been added to easily set up Tailwind CSS in your Angular projects.
You can use it when creating a new application:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ng&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; my-app&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; --style&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; tailwind&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This sets up Tailwind CSS with a minimal &lt;code&gt;.postcssrc.json&lt;/code&gt; configuration file
and adds the required dependencies (&lt;code&gt;tailwindcss&lt;/code&gt;, &lt;code&gt;@tailwindcss/postcss&lt;/code&gt;, and &lt;code&gt;postcss&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Interestingly, &lt;code&gt;ng add&lt;/code&gt; now supports adding a package that is not a schematic
and will fall back to installing the NPM package
and then try to run its schematic if it has one.
So, you can also add Tailwind CSS to an existing project with:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ng&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; tailwindcss&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Style guide 2016&lt;/h2&gt;
&lt;p&gt;If you&amp;#39;re nostalgic about the old Angular file naming conventions from 2016,
you can now generate a project following its recommendations
by using the &lt;code&gt;--file-name-style-guide=2016&lt;/code&gt; option when creating a new application.&lt;/p&gt;
&lt;p&gt;This option adds a retro vibe to your project with file names like &lt;code&gt;user.component.ts&lt;/code&gt;,
&lt;code&gt;user.pipe.ts&lt;/code&gt;, and &lt;code&gt;user.service.ts&lt;/code&gt; 🪩.&lt;/p&gt;
&lt;p&gt;The component, directive, and services name will also follow the 2016 conventions,
with a &lt;code&gt;Component&lt;/code&gt;, &lt;code&gt;Directive&lt;/code&gt;, or &lt;code&gt;Service&lt;/code&gt; suffix in their class names.&lt;/p&gt;
&lt;h2&gt;ng version&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;ng version&lt;/code&gt; command has been improved to provide more detailed information
about the packages in your Angular project (showing the requested and installed versions).
A &lt;code&gt;--json&lt;/code&gt; option has also been added to output the information in JSON format,
which can be useful for automation scripts.&lt;/p&gt;
&lt;h2&gt;Accessibility&lt;/h2&gt;
&lt;p&gt;A new &lt;code&gt;@angular/aria&lt;/code&gt; package has been introduced
to provide headless and accessible directives that implement common ARIA patterns.
They handle keyboard interactions, ARIA attributes, focus management, and screen reader support.
These directives are built on top of the CDK and developed by the Angular Material team.
The package is in developer preview in v21
and currently contains the following directives: &lt;code&gt;Accordion&lt;/code&gt;, &lt;code&gt;Autocomplete&lt;/code&gt;, &lt;code&gt;ComboBox&lt;/code&gt;, &lt;code&gt;Grid&lt;/code&gt;, &lt;code&gt;ListBox&lt;/code&gt;, &lt;code&gt;Menu&lt;/code&gt;, &lt;code&gt;Multiselect&lt;/code&gt;, &lt;code&gt;Select&lt;/code&gt;, &lt;code&gt;Tabs&lt;/code&gt;, &lt;code&gt;Toolbar&lt;/code&gt;, and &lt;code&gt;Tree&lt;/code&gt;.
We haven&amp;#39;t tested them yet,
so we&amp;#39;ll let you &lt;a href=&quot;https://next.angular.dev/guide/aria/overview&quot;&gt;explore them&lt;/a&gt; on your own.&lt;/p&gt;
&lt;h2&gt;AI&lt;/h2&gt;
&lt;p&gt;The AI section is becoming a regular section of our release review!
The CLI team worked hard on the MCP server.
It now offers 7 tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;list_projects&lt;/code&gt;: lists the Angular projects in the workspace&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get_best_practices&lt;/code&gt;: provides the latest best practices&lt;/li&gt;
&lt;li&gt;&lt;code&gt;find_examples&lt;/code&gt; (now stable): finds code examples for a given topic&lt;/li&gt;
&lt;li&gt;&lt;code&gt;search_documentation&lt;/code&gt;: searches the Angular documentation&lt;/li&gt;
&lt;li&gt;&lt;code&gt;modernize&lt;/code&gt; (still experimental): suggests modernizations for your codebase&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ai_tutor&lt;/code&gt; (new): provides interactive learning to build a &amp;quot;Smart Recipe Box&amp;quot; application&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onpush_zoneless_migration&lt;/code&gt; (new): helps migrate to OnPush and zoneless change detection&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;find_examples&lt;/code&gt; is now stable,
and has been improved to support filtering, weighted results,
and searching for specific Angular packages and versions.
The examples you add to your project can now have a frontmatter description,
with a &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;summary&lt;/code&gt; and &lt;code&gt;keywords&lt;/code&gt;.
It can also be marked as &lt;code&gt;experimental&lt;/code&gt;
if they use experimental APIs.
By default, the database has just one example for a &lt;code&gt;@if&lt;/code&gt;,
but we can expect the default database to grow over time.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;search_documentation&lt;/code&gt; has also been improved to search the documentation
for the specific Angular version of your project.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;modernize&lt;/code&gt; is still experimental,,
and now can run migrations directly.
So if you ask your favorite AI assistant
to modernize a component,
the MCP server will be able to run the necessary migrations
to update your codebase (control-flow, signal migrations, etc.).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;onpush_zoneless_migration&lt;/code&gt; is an interesting new tool
that analyzes your codebase and provides a step-by-step plan
to migrate your application to OnPush and zoneless.
It targets components and their tests,
helps you identify ZoneJS usages that need to be addressed
and suggests how to migrate to zoneless.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;The transition to &lt;strong&gt;zoneless by default&lt;/strong&gt;, the introduction of &lt;strong&gt;Signal Forms&lt;/strong&gt;
and Vitest as the new default testing framework are big news for Angular developers.&lt;/p&gt;
&lt;p&gt;Migration of existing applications to turn on zoneless change detection
will require a big effort though.
As well as for Vitest if you have thousands of Jasmine tests like we do.&lt;/p&gt;
&lt;p&gt;Signal forms have still some rough edges as they are still experimental,
but they look very promising, and are maybe a good choice for new projects?
We will keep an eye on their evolution in the coming releases,
and let you know what we think about them.&lt;/p&gt;
&lt;p&gt;Stay tuned!&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>Angular tests with Vitest browser mode</title>
    <link href="https://blog.ninja-squad.com/2025/11/18/angular-tests-with-vitest-browser-mode"/>
    <updated>2025-11-18T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2025/11/18/angular-tests-with-vitest-browser-mode</id>
    <content type="html">
      &lt;p&gt;Unit testing our Angular applications is something we take seriously.&lt;/p&gt;
&lt;p&gt;The TestBed helps, but I&amp;#39;ve always found it very low-level. 
It looks to me like it was designed mainly to test the framework itself rather than applications using the framework. 
For example, there is nothing to help you interact with the UI elements (form inputs, selects, etc.) other than the low-level DOM APIs.&lt;/p&gt;
&lt;p&gt;Recent versions, along with zoneless change detection, have improved the situation a little bit. 
We can now replace the many &lt;code&gt;fixture.detectChanges()&lt;/code&gt; calls with &lt;code&gt;await fixture.whenStable()&lt;/code&gt;, 
and let the framework detect the changes automatically, making the code under test behave more like it 
would behave in real-life. You can check out &lt;a href=&quot;https://youtu.be/JgAat9tP8Es&quot;&gt;this conference talk&lt;/a&gt; 
by Cédric Exbrayat (in French) if you want to learn more about this topic.&lt;/p&gt;
&lt;p&gt;To make tests easier to write and maintain, we have developed, and still heavily use &lt;a href=&quot;https://ngx-speculoos.ninja-squad.com/&quot;&gt;ngx-speculoos&lt;/a&gt;. 
It&amp;#39;s a thin layer on top of the TestBed, but it offers several interesting advantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;it makes it easier to interact with elements, in particular form elements&lt;/li&gt;
&lt;li&gt;it offers frequently used jasmine assertions to check the state of form and other DOM elements&lt;/li&gt;
&lt;li&gt;it drastically reduces the number of &lt;code&gt;fixture.detectChanges()&lt;/code&gt; / &lt;code&gt;fixture.whenStable()&lt;/code&gt; calls necessary&lt;/li&gt;
&lt;li&gt;with the page object pattern, it allows defining the selectors to access the elements to test once, and use them across all the tests of a suite&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Angular 21 changes everything for the better. Change detection is zoneless by default, and Vitest is now the 
default testing framework instead of Jasmine. In particular, the &lt;em&gt;Browser mode&lt;/em&gt; of Vitest makes unit testing awesome.&lt;/p&gt;
&lt;p&gt;Instead of using a Node-based DOM implementation like Jest (and Vitest by default) do, the &lt;em&gt;Browser mode&lt;/em&gt; 
allows the code under test to run in the real production environment: the browser(s) (Chromium, Firefox and Webkit). 
So we keep this feature that Karma offered.&lt;/p&gt;
&lt;p&gt;But it goes much further. Vitest comes with two killer features.&lt;/p&gt;
&lt;h2&gt;Retried assertions&lt;/h2&gt;
&lt;p&gt;Retried assertions eliminate, most of the time, the need to call &lt;code&gt;fixture.detectChanges()&lt;/code&gt; or &lt;code&gt;await fixture.whenStable()&lt;/code&gt;. 
If you&amp;#39;ve used Playwright or Cypress for end-to-end tests, you should know the principle already.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s say you want to check that the title of the page contains &amp;quot;Hello&amp;quot;. If you write:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;expect&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(title)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;toHaveTextContent&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Hello&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;that will just make that check, immediately, and only once. &lt;/p&gt;
&lt;p&gt;In order for that test to pass, you need to make sure that the asynchronous task that sets the title is done, 
and that the framework has detected the changes and updated the DOM. 
That&amp;#39;s why we litter the code with &lt;code&gt;fixture.detectChanges()&lt;/code&gt; or &lt;code&gt;await fixture.whenStable()&lt;/code&gt;. 
But Vitest allows doing the following:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; expect&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;element&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(title)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;toHaveTextContent&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Hello&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A small change, but with big implications! 
This time Vitest will execute the assertion, and retry it, again and again (every N milliseconds), 
until it passes or until the test times out. 
So if you haven&amp;#39;t waited for the fixture to be stable, no problem: the assertion will fail once, 
but by the time it retries, the framework will have stabilized and updated the DOM, and the test will pass.&lt;/p&gt;
&lt;p&gt;Imagine you&amp;#39;re using a &lt;a href=&quot;/2025/02/20/angular-http-resource&quot;&gt;resource&lt;/a&gt; and you want to test that the page displays a spinner while the resource is loading, with Jasmine and the TestBed:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;it&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;should display a spinner while loading&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; fixture&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; TestBed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;createComponent&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;MyComponent&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  await&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; fixture&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;whenStable&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  expect&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;fixture&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;nativeElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;querySelector&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;[data-testid=spinner]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;toBeTruthy&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This looks simple enough, but it doesn&amp;#39;t work: the application won&amp;#39;t become stable until the resource has loaded. 
The fix is really not easy to figure out: you need to call &lt;code&gt;TestBed.tick()&lt;/code&gt; in that case:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;it&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;should display a spinner while loading&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; fixture&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; TestBed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;createComponent&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;MyComponent&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  TestBed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;tick&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  expect&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;fixture&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;nativeElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;querySelector&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;#spinner&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;toBeTruthy&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No need to deal with these low-level details thanks to retried assertions:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;it&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;should display a spinner while loading&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; fixture&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; TestBed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;createComponent&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;MyComponent&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  await&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; expect&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;page&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;getByText&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Loading...&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;toBeVisible&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Locators, their interactivity and assertion API&lt;/h2&gt;
&lt;p&gt;Instead of using the DOM API and interacting directly with DOM elements, in a Vitest browser test, you use &lt;em&gt;locators&lt;/em&gt;.
A locator is an object which allows getting zero, one or several elements on the page 
(or inside the element of another locator).&lt;/p&gt;
&lt;p&gt;Every time you interact with the locator, it executes the query to find the element. 
This means that you can use the same locator throughout the tests of a component without worrying 
that it might be null, or stale, or not in the DOM anymore.&lt;/p&gt;
&lt;p&gt;In fact, in my tests, I use the same page object pattern as with ngx-speculoos. 
Instead of using getters to query the element(s) every time I want to interact with them, 
check their presence or their state, I simply initialize locators (see the complete example below).&lt;/p&gt;
&lt;p&gt;Vitest heavily promotes writing tests that work as if you were a user in front of the screen. 
So instead of locating elements by their ID or element names, you locate them by their text, role, label, etc.&lt;/p&gt;
&lt;p&gt;Locators, in addition to querying components, also offer an API to test the state of their element(s) 
with rich (and extensible) assertions. And they also have an interaction API to manipulate them as a user would: 
click, fill, select, etc.&lt;/p&gt;
&lt;p&gt;All this combined allows writing really expressive and simple tests suites like the following 
(we will not mock the service that it uses, but Vitest of course has a mocking API too):&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; LoginTester&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  readonly&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; fixture&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; TestBed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;createComponent&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(LoginPage)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  readonly&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; page&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;elementLocator&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;fixture&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;nativeElement)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  readonly&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; page&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;getByLabelText&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  readonly&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; page&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;getByLabelText&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  readonly&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; signIn&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; page&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;getByRole&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Sign in&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  readonly&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; page&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;getByText&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Wrong credentials, try again&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;describe&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;LoginPage&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  let&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; tester&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; LoginTester&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  beforeEach&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;    TestBed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;configureTestingModule&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      providers&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;provideRouter&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;([])]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;    tester&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; LoginTester&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  it&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;should display an empty form and no error initially&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    await&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; expect&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;element&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;tester&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;login&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;toHaveDisplayValue&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    await&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; expect&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;element&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;tester&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;toHaveDisplayValue&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    await&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; expect&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;element&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;tester&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;not&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;toBeInTheDocument&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  it&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;should validate&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    await&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; tester&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;signIn&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;click&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    await&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; expect&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;element&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;tester&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;toHaveTextContent&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;The login is required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    await&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; expect&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;element&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;tester&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;toHaveTextContent&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;The password is required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  it&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;should display an error when login fails&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    await&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; tester&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;fill&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;john&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    await&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; tester&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;fill&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;wrong-password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    await&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; tester&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;signIn&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;click&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    await&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; expect&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;element&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;tester&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;toBeVisible&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  it&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;should navigate away when login succeeds&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; router&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; TestBed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;inject&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Router&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;    vi&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;spyOn&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;router&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;navigate&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    await&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; tester&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;fill&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;john&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    await&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; tester&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;fill&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;correct-password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    await&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; tester&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;signIn&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;click&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    expect&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;router&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;navigate&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;toHaveBeenCalled&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Isn&amp;#39;t that beautiful?&lt;/p&gt;
&lt;p&gt;Another cool thing? If you edit the component or its test and save, Vitest will reexecute just that test!
Jest users had this for years, but we, poor Karma users, have been struggling with the whole test suite 
re-running on - every - single - save.&lt;/p&gt;
&lt;p&gt;I still wonder how much time a very big test suite would take (the biggest app we&amp;#39;re working on has more 
than 7500 tests), but given that Vitest can run tests in parallel, I hope it will scale reasonably well. &lt;/p&gt;
&lt;p&gt;Anyway, we won&amp;#39;t be able to rewrite all these tests any time soon.&lt;/p&gt;
&lt;p&gt;For new projects, Vitest browser mode would be my preferred choice. What would be yours?&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>Angular Signal Forms - Part 2</title>
    <link href="https://blog.ninja-squad.com/2025/11/14/angular-signal-forms-part-2"/>
    <updated>2025-11-14T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2025/11/14/angular-signal-forms-part-2</id>
    <content type="html">
      &lt;p&gt;Welcome back to our series on Angular Signal Forms!
In &lt;a href=&quot;/2025/11/04/angular-signal-forms-part-1/&quot;&gt;Part 1&lt;/a&gt;,
we covered the basics: creating forms, handling submissions, and adding validation.&lt;/p&gt;
&lt;p&gt;In this second part, we&amp;#39;ll explore all the advanced features:
custom validators, cross-field validation, asynchronous validation,
dynamic field behavior, debouncing form updates, custom form components, sub forms,
and other powerful capabilities that make Signal Forms a compelling choice
for complex form scenarios.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;img class=&quot;rounded img-fluid&quot; style=&quot;max-width: 60%&quot; src=&quot;/assets/images/angular_gradient.webp&quot; alt=&quot;Angular logo&quot; /&gt;
&lt;/p&gt;

&lt;h2&gt;Custom validation with &lt;code&gt;validate()&lt;/code&gt; and &lt;code&gt;validateTree()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;You can write your own custom validators,
either synchronous or asynchronous, and apply them with &lt;code&gt;validate()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s start with a synchronous validator,
that checks that the password of our &lt;code&gt;Register&lt;/code&gt; form is strong enough.&lt;/p&gt;
&lt;p&gt;A validator is simply a function that takes a &lt;code&gt;ChildFieldContext&lt;/code&gt; as an argument,
and returns either &lt;code&gt;undefined&lt;/code&gt; if the field is valid,
or a &lt;code&gt;ValidationError&lt;/code&gt; if the field is invalid.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;ChildFieldContext&lt;/code&gt; provides useful methods to get the value or state of the field
(as well as the value or state of other fields, more on that later).&lt;/p&gt;
&lt;p&gt;Validators are typed, which is a great improvement over previous form systems.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// password is strong enough&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;validate&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;context&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ChildFieldContext&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  isTooWeak&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(context&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; kind&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;too-weak&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Password is too weak&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; undefined&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is also possible to add cross-field validation,
by adding the validator to the parent field,
and checking the values of the sub-fields.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// password is different from email&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;validate&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; context&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; context&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ===&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; password&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    ?&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;        kind&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;password-different-from-email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;        message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Password should not be the same as email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    :&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; undefined;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In your template,
you can display this cross-field validation error
by checking the errors on the form itself:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;accountForm&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;touched&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;accountForm&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;valid&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;form-errors&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    @for&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (error &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; accountForm&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;errors&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; track&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;kind) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;message &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alternatively, you can put the cross-field validation error on a specific field,
using &lt;code&gt;validateTree()&lt;/code&gt; instead of &lt;code&gt;validate()&lt;/code&gt;.
This function works like &lt;code&gt;validate()&lt;/code&gt;,
but allows returning errors targeting specific sub-fields of the tree.
For example, to validate that the password is different from the email,
but show the error on the password field:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;validateTree&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; context&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; context&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ===&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; password&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    ?&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;        // 👇 targets the password field&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;        field&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; context&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;field&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;        kind&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;password-different-from-email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;        message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Password should not be the same as email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    :&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; undefined;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is also possible to add a validation to a field
and get the value of another field by using the &lt;code&gt;valueOf()&lt;/code&gt; method.
The same example can be written like this:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// 👇 the validator is defined on the password field&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;validate&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; context&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇 get the value of the email field&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; context&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;valueOf&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; context&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ===&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; password&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    ?&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;        kind&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;is-different-from-email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;        message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Password should not be the same as email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    :&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; undefined;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Extracting and applying schemas with &lt;code&gt;apply()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;To avoid duplicating validation logic across forms,
you can extract it into reusable schemas,
that can then be applied to fields using the &lt;code&gt;apply()&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;If both our login and password fields should be required and with a minimum length,
we can extract this logic into a schema:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; requiredAndMinLengthSchema &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; schema&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;field&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  required&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;field&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;This field is required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  minLength&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;field&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Minimum length is 3 characters&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we can apply this schema to both fields in our forms:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;protected readonly accountForm &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; form&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; context&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇 apply the same schema to both fields&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  apply&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;context&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; requiredAndMinLengthSchema&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  apply&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;context&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; requiredAndMinLengthSchema&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A schema can also be applied to all elements of an array using &lt;code&gt;applyEach()&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;protected readonly eventForm &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; form&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  signal&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    location&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    participants&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ced&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;  context&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // 👇 apply the same schema to all participants&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    applyEach&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;context&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;participants&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; requiredAndMinLengthSchema&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By the way, to display an array of fields in the template,
all you need is a plain old &lt;code&gt;@for&lt;/code&gt; loop.
No need for any special directive.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@for&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (participant &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; eventForm&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;participants&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; track&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; participant) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;participant&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [for]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;`participant-${$index}`&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Username&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [id]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;`participant-${$index}`&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [field]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;participant&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    @if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;participant&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;touched&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;participant&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;valid&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [id]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;`participant-${$index}-errors`&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;        @for&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (error &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; participant&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;errors&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; track&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;kind) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;          &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;message &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;applyEach()&lt;/code&gt; also works with objects,
applying the schema to all properties.
For example, if we want to make all fields required:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;protected readonly loginForm &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; form&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  signal&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;  context&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // 👇 apply the required schema to all fields&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    applyEach&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;context&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; requiredSchema&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Asynchronous validation with &lt;code&gt;validateAsync()&lt;/code&gt; and &lt;code&gt;validateHttp()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The validation can also be asynchronous thanks to the &lt;code&gt;validateAsync()&lt;/code&gt; function,
which uses a &lt;code&gt;Resource&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// email is not already registered (async validation)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;validateAsync&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  params&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ChildFieldContext&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  factory&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; Signal&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; undefined&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    resource&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;      // 👇 Params contains the `email` signal and is used to trigger the resource&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;      params&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;      // the loader makes an HTTP call to check if the email is already registered&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;      loader&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;loaderParams&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ResourceLoaderParams&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; undefined&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;        // returns true if the email is already registered&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;        await&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;userService&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;isRegistered&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(loaderParams&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;params)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // 👇 This is called with the result of the resource&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    onSuccess&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; isRegistered&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; boolean&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; })&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;      response&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;isRegistered&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;        ?&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;            kind&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;email-already-registered&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;            message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Email is already registered&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;          }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;        :&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; undefined,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // 👇 This is called if the resource fails&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    onError&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;      (&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;        kind&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;email-check-failed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;        message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Could not verify if the email is already registered&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The resource is automatically called when the value of the field changes,
and the field is marked as &lt;code&gt;pending()&lt;/code&gt; while waiting for the result of the resource.
When the resource resolves,
if the &lt;code&gt;onSuccess&lt;/code&gt; function returns an error,
the error is added to the &lt;code&gt;errors()&lt;/code&gt; of the field.&lt;/p&gt;
&lt;p&gt;As an alternative, if you need to call an HTTP endpoint to validate a field,
you can use a &lt;code&gt;httpResource()&lt;/code&gt; with the &lt;code&gt;validateHttp()&lt;/code&gt; function:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// email is not already registered (async validation)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;validateHttp&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇 httpResource is triggered when the email signal changes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  request&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ChildFieldContext&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; `&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;/api/users/check?email=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  onSuccess&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; isRegistered&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; boolean&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; })&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;    response&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;isRegistered&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      ?&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;          kind&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;email-already-taken&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;          message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Email is already taken&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      :&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; undefined,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  onError&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      kind&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;email-check-failed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Could not verify if the email is already taken&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In that case, you only need to provide the request URL.&lt;/p&gt;
&lt;h2&gt;Server errors&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;submit&lt;/code&gt; function we saw earlier has another interesting feature:
if the action you provide returns errors,
they are automatically added to the &lt;code&gt;errors()&lt;/code&gt; of the corresponding fields
(or to the form if you don&amp;#39;t provide a field).&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; submit&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;loginForm&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; form&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; form&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  try&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    await&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;userService&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;authenticate&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; password&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; catch&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // 👇 add an error to the form&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; Error&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; kind&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;invalid-credentials&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Dynamic behavior&lt;/h2&gt;
&lt;p&gt;A more realistic form often has some dynamic behavior,
for example, enabling/disabling or hiding/displaying fields based on the value of other fields,
or adding/removing validators.&lt;/p&gt;
&lt;p&gt;To hide a field, you can use the &lt;code&gt;hidden()&lt;/code&gt; function,
which lets you specify when the field should be hidden or not,
based on the state of the form.
When a field is hidden, it is excluded from validation.
In the template, you can then use an &lt;code&gt;@if&lt;/code&gt; block to display the field only if it&amp;#39;s not hidden.&lt;/p&gt;
&lt;p&gt;Similarly, to disable a field, you can use the &lt;code&gt;disabled()&lt;/code&gt; function in the form schema.
Here, the password field is disabled unless the login is valid:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;protected readonly loginForm &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; form&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;credentials&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  required&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;login&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇 disable the password field until a valid login is provided&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  disabled&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ({&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; stateOf&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; })&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;stateOf&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;login&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;valid&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can go even further and return a string from the disabled logic,
in order to populate the &lt;code&gt;disabledReasons()&lt;/code&gt; of the field.&lt;/p&gt;
&lt;p&gt;The last function to know about is &lt;code&gt;readonly()&lt;/code&gt;,
which makes a field read-only as you imagine.
This is useful when you want to display an input that the user may not edit,
but that should still be submitted with the form.
&lt;code&gt;disabled()&lt;/code&gt; and &lt;code&gt;readonly()&lt;/code&gt; automatically update the HTML attributes
of the corresponding field in the template:
you don&amp;#39;t need to do anything special for an input to be disabled in the template part of the form.&lt;/p&gt;
&lt;p&gt;NOTE: Disabled fields do not behave the same way as in reactive forms:
their value is still part of the form value when submitting it.
The positive side is that you don&amp;#39;t have to deal
with the fact that all properties are potentially undefined.
The negative side is that you need to be careful before sending this value to the server:
it could be invalid if it comes from a disabled field.
The same goes for hidden fields.&lt;/p&gt;
&lt;p&gt;These functions can be used together to create complex dynamic behavior,
and they can be applied conditionally.
The second parameter of the &lt;code&gt;form()&lt;/code&gt; function is &lt;em&gt;not&lt;/em&gt; a reactive function,
which means you &lt;em&gt;can&amp;#39;t&lt;/em&gt; use if/else conditions based on signals.
You need to use &lt;code&gt;applyWhenValue()&lt;/code&gt;/&lt;code&gt;applyWhen()&lt;/code&gt; to apply these functions conditionally.&lt;/p&gt;
&lt;p&gt;For example, to make a field mandatory only when a user is not admin
(and let&amp;#39;s say this info is stored in a signal called &lt;code&gt;isAdmin&lt;/code&gt;):&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;protected readonly accountForm &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; form&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; form&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇 the birth year field is required only when the user is not admin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  applyWhenValue&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;    form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; !this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;userService&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;isAdmin&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;    form&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;      required&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;birthYear&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Birth year is required for non-admin users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  )&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the logic depends on another field,
you can use &lt;code&gt;applyWhen()&lt;/code&gt; instead,
which gives you access to the form and its fields via &lt;code&gt;valueOf&lt;/code&gt;/&lt;code&gt;stateOf&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;protected readonly accountForm &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; form&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; form&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇 the birth year field is required only when the isAdmin checkbox is not checked&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  applyWhen&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;    form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;    context&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;context&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;valueOf&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;isAdmin&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;    form&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;      required&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;birthYear&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Birth year is required for non-admin users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  )&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Debouncing form updates with &lt;code&gt;debounce()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Sometimes you want to control when form control changes are synchronized to the form model.
For example, you might want to delay validation while a user is still typing,
to avoid triggering expensive validation checks on every keystroke.&lt;/p&gt;
&lt;p&gt;Signal forms provide a &lt;code&gt;debounce()&lt;/code&gt; function that allows you to manage the timing of form field updates:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;protected readonly accountForm &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; form&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; form&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇 let&apos;s say the computation is expensive, and we want to debounce it&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  debounce&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 500&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // password is strong enough&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  validate&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;context&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ChildFieldContext&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    isTooWeak&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;context&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; kind&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;too-weak&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Password is too weak&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; undefined&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  )&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When a debounce rule is applied to a field,
the &lt;code&gt;value&lt;/code&gt; signal may lag behind the &lt;code&gt;controlValue&lt;/code&gt; signal.
The &lt;code&gt;controlValue&lt;/code&gt; represents the current value in the form control (what the user just typed),
while &lt;code&gt;value&lt;/code&gt; represents the debounced value that gets synchronized to the form model.&lt;/p&gt;
&lt;p&gt;The debounce delay can be a fixed number (in milliseconds)
or a function that returns a promise.&lt;/p&gt;
&lt;h2&gt;Custom form components with &lt;code&gt;FormValueControl&lt;/code&gt; and &lt;code&gt;FormCheckboxControl&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Sometimes we need to build custom form components.
We used to have &lt;code&gt;ControlValueAccessor&lt;/code&gt; for that in previous form systems,
but with signal forms, there is a new and simpler way to do that:
by implementing the &lt;code&gt;FormUiControl&lt;/code&gt; interface,
or, more accurately, one of its children interfaces &lt;code&gt;FormCheckboxControl&lt;/code&gt; (for boolean-like controls)
and &lt;code&gt;FormValueControl&lt;/code&gt; (for other types of values).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Custom form components that use &lt;code&gt;ControlValueAccessor&lt;/code&gt; are still supported in signal forms,
but it&amp;#39;s recommended to use these new interfaces for new components.&lt;/p&gt;
&lt;p&gt;These interfaces only define the inputs and models your component should have,
and Angular will bind the &lt;code&gt;Field&lt;/code&gt; directive state into these signals automatically.&lt;/p&gt;
&lt;p&gt;The properties to implement are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;value&lt;/code&gt;: (only for &lt;code&gt;FormValueControl&lt;/code&gt;) a model input defining the value of the field&lt;/li&gt;
&lt;li&gt;&lt;code&gt;checked&lt;/code&gt;: (only for &lt;code&gt;FormCheckboxControl&lt;/code&gt;) a model input defining whether the field is checked or not&lt;/li&gt;
&lt;li&gt;&lt;code&gt;touched&lt;/code&gt;: model input defining whether the field has been touched or not&lt;/li&gt;
&lt;li&gt;&lt;code&gt;disabled&lt;/code&gt;/&lt;code&gt;disabledReasons&lt;/code&gt;/&lt;code&gt;readonly&lt;/code&gt;/&lt;code&gt;hidden&lt;/code&gt;/&lt;code&gt;dirty&lt;/code&gt;: inputs containing the state of the field&lt;/li&gt;
&lt;li&gt;&lt;code&gt;errors&lt;/code&gt;/&lt;code&gt;invalid&lt;/code&gt;/&lt;code&gt;pending&lt;/code&gt;: inputs containing the validation state of the field&lt;/li&gt;
&lt;li&gt;&lt;code&gt;required&lt;/code&gt;/&lt;code&gt;minLength&lt;/code&gt;/&lt;code&gt;maxLength&lt;/code&gt;/&lt;code&gt;min&lt;/code&gt;/&lt;code&gt;max&lt;/code&gt;/&lt;code&gt;pattern&lt;/code&gt;: inputs containing the built-in validators applied to the field&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All these properties are optionals,
except &lt;code&gt;value&lt;/code&gt; or &lt;code&gt;checked&lt;/code&gt; depending on the interface you implement.
Most properties are read-only inputs,
except &lt;code&gt;value&lt;/code&gt;, &lt;code&gt;checked&lt;/code&gt;, and &lt;code&gt;touched&lt;/code&gt;, which are model inputs,
as the component is expected to update them.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s build a &lt;code&gt;Rating&lt;/code&gt; component,
that allows the user to select a rating from 1 to 5.
The value will be a number, so let&amp;#39;s implement the &lt;code&gt;FormValueControl&amp;lt;number&amp;gt;&lt;/code&gt; interface:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  selector&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;app-rating&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; `&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;    @let&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; v &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    @for&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (pickableValue &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; pickableValues&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; track&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; pickableValue) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;        [class.selected]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;v != null &amp;#x26;&amp;#x26; pickableValue &amp;#x3C;= v&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;        type&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;        (click)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;value.set(pickableValue)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;        [disabled]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;disabled()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;        (blur)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;touched.set(true)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;        {{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; pickableValue &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;  `&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  styles&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;selected&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#B2CCD6&quot;&gt; background-color&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; yellow &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; Rating&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; FormValueControl&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  readonly&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; model&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  readonly&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; touched&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; model&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  readonly&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; disabled&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; input&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  protected&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; readonly&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; pickableValues&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The template is straightforward.
We iterate over the possible ratings
and display a button for each rating.
Clicking a button updates the &lt;code&gt;value&lt;/code&gt;.
And when it loses focus (blur event),
we mark the field as &lt;code&gt;touched&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Changing the value of the model inputs automatically updates the state of the field in the form.
And in the other direction,
changing the field state automatically update the inputs of the component.&lt;/p&gt;
&lt;p&gt;Our component can then be used in a form like this:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;app-rating&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;rating&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [field]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;movieForm.rating&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Sub forms&lt;/h2&gt;
&lt;p&gt;Sometimes you don&amp;#39;t want to define the entire form in a single component.
You may want to split it into several sub-forms, each defined in its own component.
With signal forms, this is easy to do by passing a field to the child component.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s say our user form has an address sub-form:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;protected readonly user &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; signal&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  firstname&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  lastname&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  address&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    street&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    zipcode&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    city&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;protected readonly userForm &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; form&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  required&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;firstname&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;First name is required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  required&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;lastname&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Last name is required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇the address schema can be defined separately and reused&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  apply&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;address&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; addressSchema&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can define an &lt;code&gt;Address&lt;/code&gt; component that accepts a &lt;code&gt;FieldTree&lt;/code&gt; for the address:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  selector&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;app-address-form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; `&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;    @let&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; address &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;addressField()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;      @let&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; number &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;address&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [field]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;      @if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;touched&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; number&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;invalid&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;        &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;          @for&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (error &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; number&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;errors&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; track&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;kind) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;            &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;message &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;          }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;        &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;street&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [field]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;address.street&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;zipcode&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [field]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;address.zipcode&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;city&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [field]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;address.city&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;  `&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  imports&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [Field]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; AddressForm&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  readonly&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; addressField&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;FieldTree&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;AddressModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we can use our &lt;code&gt;Address&lt;/code&gt; component in the user registration template:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;app-address-form&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [addressField]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;userForm.address&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That makes it really easy to split a form into several components!&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Signal forms bring a new way to build forms in Angular,
based on signals and with a fresh approach to validation and reactivity.
While still experimental for now,
they already offer a lot of interesting features
that make building forms easier and more enjoyable
than before.&lt;/p&gt;
&lt;p&gt;Among the benefits, the type safety is better than before;
cross-field validation is easier to implement (no need to use &lt;code&gt;FormGroup&lt;/code&gt; anymore);
and building custom form components is simpler as well (&lt;code&gt;FormValueControl&lt;/code&gt; is much simpler than &lt;code&gt;ControlValueAccessor&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;We lose the &lt;code&gt;ng-valid&lt;/code&gt;/&lt;code&gt;ng-dirty&lt;/code&gt;/... CSS classes that were automatically added to form controls,
but we can easily recreate them using the properties of the &lt;code&gt;FieldTree&lt;/code&gt;,
even if it requires a bit more work in the template.&lt;/p&gt;
&lt;p&gt;A few things would be great to have in the future,
like better support for displaying error messages in the template
(iterating over &lt;code&gt;errors()&lt;/code&gt; is a bit low-level for most use cases).&lt;/p&gt;
&lt;h2&gt;What&amp;#39;s next?&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ve now covered the comprehensive features of signal forms:
from creating forms and handling submissions to custom validators,
asynchronous validation, server error handling, dynamic field behavior,
debouncing form updates, custom form components, and sub forms.&lt;/p&gt;
&lt;p&gt;Key takeaways from this series:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Signal forms provide a new signal-based approach to forms in Angular&lt;/li&gt;
&lt;li&gt;They offer better type safety and easier cross-field validation than previous form systems&lt;/li&gt;
&lt;li&gt;Custom validators are simple functions using &lt;code&gt;validate()&lt;/code&gt; that return validation error objects&lt;/li&gt;
&lt;li&gt;Asynchronous validation uses &lt;code&gt;validateAsync()&lt;/code&gt; or &lt;code&gt;validateHttp()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Server errors can be automatically mapped to form fields&lt;/li&gt;
&lt;li&gt;Dynamic behavior is achieved via &lt;code&gt;applyWhen()&lt;/code&gt; and &lt;code&gt;applyWhenValue()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Form updates can be debounced using &lt;code&gt;debounce()&lt;/code&gt; to control the timing of synchronization&lt;/li&gt;
&lt;li&gt;Custom form components use &lt;code&gt;FormValueControl&lt;/code&gt;, which is simpler than &lt;code&gt;ControlValueAccessor&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Sub forms can be easily created by passing fields to child components&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Signal forms are still experimental but show great promise
for making form development more intuitive and type-safe in Angular applications!&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>Angular Signal Forms - Part 1</title>
    <link href="https://blog.ninja-squad.com/2025/11/04/angular-signal-forms-part-1"/>
    <updated>2025-11-04T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2025/11/04/angular-signal-forms-part-1</id>
    <content type="html">
      &lt;p&gt;In Angular v21, developers will have a new way,
experimental for now, to build forms: &lt;strong&gt;Signal Forms&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;After years of working with template-driven forms (&lt;code&gt;ngModel&lt;/code&gt;)
and reactive forms (&lt;code&gt;formGroup&lt;/code&gt;/&lt;code&gt;formControl&lt;/code&gt;),
we now have a third approach that&amp;#39;s entirely based on signals,
available in the &lt;code&gt;@angular/forms/signals&lt;/code&gt; package.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;img class=&quot;rounded img-fluid&quot; style=&quot;max-width: 60%&quot; src=&quot;/assets/images/angular_gradient.webp&quot; alt=&quot;Angular logo&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;This is the first part of our series on Angular Signal Forms.
In this article, we&amp;#39;ll explore the basics:
creating forms, handling submissions, and adding validation.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s dive in! 🚀&lt;/p&gt;
&lt;h2&gt;Creating a form with &lt;code&gt;form()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;As this new way is based on signals,
the first thing to do in your component is to define a signal that will hold
the value of the form.
Then you can create a &lt;code&gt;FieldTree&lt;/code&gt; to edit the value of this signal,
using the &lt;code&gt;form()&lt;/code&gt; function from the &lt;code&gt;@angular/forms/signals&lt;/code&gt; package.&lt;/p&gt;
&lt;p&gt;Here I want to write a &lt;code&gt;Login&lt;/code&gt; component,
where the user inputs their credentials:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// 👇 signal to hold the form credentials&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;private readonly credentials &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; signal&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// 👇 form created from the credentials signal (type is `FieldTree`)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;protected readonly loginForm &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; form&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;credentials)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we need to bind each &lt;code&gt;input&lt;/code&gt;/&lt;code&gt;select&lt;/code&gt;/&lt;code&gt;textarea&lt;/code&gt; to a field in the form.
This is done using a single directive, &lt;code&gt;Field&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; (submit)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;authenticate($event)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [field]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;loginForm.login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [field]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;loginForm.password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;submit&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Log in&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;#39;s it!
With just the &lt;code&gt;[field]&lt;/code&gt; directive,
your inputs are automatically bound to the form fields.
A change on an input updates the corresponding property of the signal,
and a change to the signal updates the input value.&lt;/p&gt;
&lt;h2&gt;Submitting the form with &lt;code&gt;submit()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;To submit the form, you can listen to the native &lt;code&gt;submit&lt;/code&gt; event on the &lt;code&gt;form&lt;/code&gt; element
and call a method of your component.&lt;/p&gt;
&lt;p&gt;In this method, you can then use the &lt;code&gt;submit()&lt;/code&gt; function from the &lt;code&gt;@angular/forms/signals&lt;/code&gt; package
to handle the submission of the form.
This function:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Marks all fields as touched&lt;/li&gt;
&lt;li&gt;Checks the form validity&lt;/li&gt;
&lt;li&gt;If valid, calls your provided async action with the form as an argument&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The argument is the same object, a &lt;code&gt;FieldTree&lt;/code&gt;,
as the &lt;code&gt;loginForm&lt;/code&gt; returned by the &lt;code&gt;form()&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;FieldTree&lt;/code&gt; object is a key concept in signal forms.
Your &lt;code&gt;loginForm&lt;/code&gt; is a &lt;code&gt;FieldTree&lt;/code&gt;, and so are &lt;code&gt;loginForm.login&lt;/code&gt; and &lt;code&gt;loginForm.password&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;FieldTree&lt;/code&gt;, like a &lt;code&gt;Signal&lt;/code&gt;, is an object that is also a function.
If you call it (&lt;code&gt;loginForm()&lt;/code&gt;),
it returns a &lt;code&gt;FieldState&lt;/code&gt; object with several signal properties
that represent the state of the field:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;value()&lt;/code&gt;: the current value of the field (may be debounced)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;controlValue()&lt;/code&gt;: the current value in the form control (always up-to-date)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;touched()&lt;/code&gt;: whether the field has been touched or not&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dirty()&lt;/code&gt;: whether the field is pristine or not&lt;/li&gt;
&lt;li&gt;&lt;code&gt;disabled()&lt;/code&gt;: whether the field is disabled or not&lt;/li&gt;
&lt;li&gt;&lt;code&gt;disabledReasons()&lt;/code&gt;: if the field is disabled, the reasons why&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hidden()&lt;/code&gt;: whether the field is hidden or not&lt;/li&gt;
&lt;li&gt;&lt;code&gt;readonly()&lt;/code&gt;: whether the field is readonly or not&lt;/li&gt;
&lt;li&gt;&lt;code&gt;submitting()&lt;/code&gt;: whether the field is being submitted&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some properties are related to validation, a topic we cover below:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pending()&lt;/code&gt;: whether the field is pending (async validators running)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;valid()&lt;/code&gt;: whether the field is valid (all validators passed).
Note that &lt;code&gt;valid()&lt;/code&gt; is false until all async validators are done.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;invalid()&lt;/code&gt;: whether the field is invalid&lt;/li&gt;
&lt;li&gt;&lt;code&gt;errors()&lt;/code&gt;: the errors of the field (if any)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;errorSummary()&lt;/code&gt;: the errors of the field and its sub-fields (if any)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It also has a few methods to change the state of the field:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;reset()&lt;/code&gt; to mark the field as pristine and untouched (but does not reset the value)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;markAsTouched()&lt;/code&gt;/&lt;code&gt;markAsDirty()&lt;/code&gt; to mark the field as touched/dirty.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can also grab the &lt;code&gt;FieldState&lt;/code&gt; of a sub-field using &lt;code&gt;loginForm.login()&lt;/code&gt; for example,
and each property then represents the state of that sub-field (its value, dirtiness, etc).&lt;/p&gt;
&lt;p&gt;So, to come back to our form submission, we can write:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;protected async &lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;authenticate&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(event: SubmitEvent) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇 prevents the default browser behavior&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  event&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;preventDefault&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇 submits the form if it&apos;s valid by calling the authenticate method (a promise)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  await&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; submit&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;loginForm&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; form&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; form&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;userService&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;authenticate&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; password&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that the function that you pass to &lt;code&gt;submit()&lt;/code&gt; must return a Promise.
So if your service returns an &lt;code&gt;Observable&lt;/code&gt;,
you&amp;#39;ll have to convert it to a promise using, for example,
the &lt;code&gt;firstValueFrom()&lt;/code&gt; function from &lt;code&gt;rxjs&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s now add some validation to our form.&lt;/p&gt;
&lt;h2&gt;Adding validation with built-in validators&lt;/h2&gt;
&lt;p&gt;Angular provides a validation system based on functions
that can be used to programmatically constrain the value of a field.&lt;/p&gt;
&lt;p&gt;As with the previous form systems, there are two types of validators:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;synchronous validators, that run immediately&lt;/li&gt;
&lt;li&gt;asynchronous validators, that return a &lt;code&gt;Promise&lt;/code&gt; and only run if all the synchronous validators on the field pass&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The framework itself provides some built-in synchronous validators,
the same as those it provides for reactive and template-driven forms:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;required(field)&lt;/code&gt; to mark a field as required&lt;/li&gt;
&lt;li&gt;&lt;code&gt;minLength(field, length)&lt;/code&gt; to set a minimum length (for strings and arrays)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maxLength(field, length)&lt;/code&gt; to set a maximum length (for strings and arrays)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;min(field, min)&lt;/code&gt; to set a minimum value (for numbers)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;max(field, max)&lt;/code&gt; to set a maximum value (for numbers)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;email(field)&lt;/code&gt; to validate an email address&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pattern(field, pattern)&lt;/code&gt; to validate a value against a regex pattern&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The functions take the field to validate as the first argument,
and other arguments depending on the validator.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s build another &lt;code&gt;Register&lt;/code&gt; form,
allowing the user to create an account:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;protected readonly accountForm &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; form&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    signal&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // 👇 add validators to the fields, with their error messages&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;    form&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;      // email is mandatory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;      required&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Email is required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;      // must be a valid email&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;      email&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Email is not valid&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;      // password is mandatory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;      required&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Password is required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;      // should have at least 6 characters&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;      minLength&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 6&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;        // can also be a function, if you need to access the current value/state of the field&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;        message&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; password&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; `&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Password should have at least 6 characters but has only &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each validator will then run when the value of the field changes.
If the validation fails, a &lt;code&gt;ValidationError&lt;/code&gt; is added to the &lt;code&gt;errors()&lt;/code&gt; property of the field.
A &lt;code&gt;ValidationError&lt;/code&gt; is an object with several properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kind&lt;/code&gt;: the kind of error (for example &lt;code&gt;required&lt;/code&gt;, &lt;code&gt;minLength&lt;/code&gt;, etc)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;field&lt;/code&gt;: the field that caused the error&lt;/li&gt;
&lt;li&gt;&lt;code&gt;message&lt;/code&gt;: an optional human-readable message. There is no message by default,
you need to provide it yourself when applying the validator if you want one.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some validators can add more properties to the error,
for example, the &lt;code&gt;minLength&lt;/code&gt; validator adds a &lt;code&gt;minLength&lt;/code&gt; property to the error,
so you can access it when displaying the error message.&lt;/p&gt;
&lt;p&gt;These errors can be displayed in the template
by iterating over the &lt;code&gt;errors()&lt;/code&gt; property of the field:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [field]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;accountForm.email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;@let&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; email &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;accountForm&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;email()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;touched&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;valid&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;email-errors&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  @for&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (error &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;errors&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; track&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;kind) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;message &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The built-in validators do more than they used to:
they also add a &lt;code&gt;property&lt;/code&gt; on the field.
This property can be useful to know if a validator is applied to a field.
For example, in the template, you can add an asterisk next to the label of required fields:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  @let&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; isEmailRequired &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;accountForm&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;email()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;metadata(REQUIRED)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  @if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;isEmailRequired&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;metadata(REQUIRED)&lt;/code&gt; method returns a signal,
and its value can be true or false.
But some validators store additional details in this metadata.
For example, the signal returned by &lt;code&gt;metadata(MIN_LENGTH)&lt;/code&gt; contains the minimum length.&lt;/p&gt;
&lt;h2&gt;Standard schema validation with &lt;code&gt;validateStandardSchema()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;In addition to the previous built-in validators,
signal forms offer a new way to define the field&amp;#39;s constraints,
by using a schema validation.&lt;/p&gt;
&lt;p&gt;A few libraries have made this popular lately, like &lt;a href=&quot;https://zod.dev/&quot;&gt;Zod&lt;/a&gt;
or &lt;a href=&quot;https://valibot.dev/&quot;&gt;Valibot&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Both allow you to define a schema to represent your data,
using functions to define the type of each field,
and to add constraints to these fields.
These libraries and others even joined their effort to define a standard:
&lt;a href=&quot;https://standardschema.dev/&quot;&gt;Standard Schema&lt;/a&gt;,
which provides a common interface, called &lt;code&gt;StandardSchemaV1&lt;/code&gt;, that libraries can use.&lt;/p&gt;
&lt;p&gt;Angular relies on this standard
and offers a &lt;code&gt;validateStandardSchema()&lt;/code&gt; function
which accepts such a &lt;code&gt;StandardSchemaV1&lt;/code&gt; schema.&lt;/p&gt;
&lt;p&gt;This schema can be defined with whatever library you prefer.
Let&amp;#39;s use Zod Mini to define a validation schema for our &lt;code&gt;Register&lt;/code&gt; form:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  validateStandardSchema&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;    form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;    z&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; email&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; z&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;check&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;z&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; z&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;check&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;z&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;minLength&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  )&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we don&amp;#39;t define error messages.
The errors will be generated automatically by the &lt;code&gt;validateStandardSchema()&lt;/code&gt; function
which returns errors of type &lt;code&gt;StandardSchemaValidationError&lt;/code&gt;.
These errors have the same properties
as the previous &lt;code&gt;ValidationError&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For example, if you input a too short password,
you&amp;#39;ll get an error like this:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Too small: expected string to have &gt;=6 characters&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can be customized as well,
as Zod Mini allows defining error messages when defining the schema,
using &lt;code&gt;z.string().check(z.minLength(6, { message: issue =&amp;gt; `Password should have at least ${issue.minimum} characters` }))&lt;/code&gt; for example.&lt;/p&gt;
&lt;h2&gt;What&amp;#39;s Next?&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ve covered the fundamentals of Angular Signal Forms:
creating forms, handling submissions, and adding basic validation
with built-in validators or using schema validation with libraries like Zod.&lt;/p&gt;
&lt;p&gt;In the next part, we&amp;#39;ll explore more advanced topics:
like creating custom validators, cross-field validation, and asynchronous validation.&lt;/p&gt;
&lt;p&gt;Stay tuned for Part 2!&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>What&apos;s new in Angular 20.3?</title>
    <link href="https://blog.ninja-squad.com/2025/09/11/what-is-new-angular-20.3"/>
    <updated>2025-09-11T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2025/09/11/what-is-new-angular-20.3</id>
    <content type="html">
      &lt;p&gt;Angular&amp;nbsp;20.3.0 is here!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;a href=&quot;https://github.com/angular/angular/releases/tag/20.3.0&quot;&gt;
    &lt;img class=&quot;img-fluid&quot; style=&quot;max-width: 60%;&quot; src=&quot;/assets/images/angular_gradient.webp&quot; alt=&quot;Angular logo&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Angular v20 will be one of the very few versions to have a third minor release.
The main reason is a security patch for a vulnerability in the &lt;code&gt;platform-server&lt;/code&gt;/&lt;code&gt;ssr&lt;/code&gt; packages. The fix is a breaking change which was released across all active LTS versions.&lt;/p&gt;
&lt;h2&gt;Vulnerability fix in platform-server and ssr&lt;/h2&gt;
&lt;p&gt;The vulnerability is described on the Angular repo: &lt;a href=&quot;https://github.com/angular/angular/security/advisories/GHSA-68x2-mx4q-78m7&quot;&gt;CVE-2025-59052&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As explained there, an attacker could potentially send multiple requests and inspect responses for leaked information from other users&amp;#39; requests in SSR applications.&lt;/p&gt;
&lt;p&gt;The cause is that the platform injector was shared globally during SSR.
When multiple requests were processed concurrently,
they could share or overwrite this global state,
causing one request to respond with data meant for a different request
(which could lead to bugs in addition to being a security vulnerability).&lt;/p&gt;
&lt;p&gt;Three APIs received breaking changes to address this issue:
&lt;code&gt;bootstrapApplication&lt;/code&gt;, &lt;code&gt;getPlatform&lt;/code&gt;, and &lt;code&gt;destroyPlatform&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The new approach introduces a &lt;code&gt;BootstrapContext&lt;/code&gt;
that is passed to the &lt;code&gt;bootstrapApplication&lt;/code&gt; function.
This context provides a platform reference that is scoped to the individual request,
ensuring that each server-side render has an isolated platform injector.&lt;/p&gt;
&lt;p&gt;Instead of:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; bootstrap &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  bootstrapApplication&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(AppComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; config)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;you now need to do:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; bootstrap &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;context&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; BootstrapContext&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  bootstrapApplication&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(AppComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; config&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; context)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;getPlatform&lt;/code&gt; and &lt;code&gt;destroyPlatform&lt;/code&gt; now returns &lt;code&gt;null&lt;/code&gt; and are no-op on the server.&lt;/p&gt;
&lt;p&gt;A schematic has been included in the release to help you migrate your code,
so you just have to run &lt;code&gt;ng update @angular/core&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Extended diagnostics&lt;/h2&gt;
&lt;p&gt;The Angular compiler already checks that signals are properly invoked in interpolations and bindings.
The extended diagnostics in v20.3 now also check them in &lt;code&gt;@if&lt;/code&gt; and &lt;code&gt;@switch&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;✘ [ERROR] NG8109: user is a function and should be invoked: user() [plugin angular-compiler]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    src/app/home/home.html:10:8:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      10 │   @if (!user) {&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Angular CLI&lt;/h2&gt;
&lt;p&gt;The CLI was also released in version 20.3.0,
with the same security fix as above for &lt;code&gt;@angular/ssr&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The only notable change that I noticed otherwise is that the variable names
are now kept when serving the application in dev mode.
This means the error messages will no longer contain weird underscores like &lt;code&gt;_App&lt;/code&gt; or &lt;code&gt;_UserService&lt;/code&gt;, which is a nice improvement for debugging.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s all for this small release.
The next one will be v21, and will include experimental signal forms.
We have a dedicated article about it coming soon, so stay tuned!&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>What&apos;s new in Angular 20.2?</title>
    <link href="https://blog.ninja-squad.com/2025/08/20/what-is-new-angular-20.2"/>
    <updated>2025-08-20T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2025/08/20/what-is-new-angular-20.2</id>
    <content type="html">
      &lt;p&gt;Angular&amp;nbsp;20.2.0 is here!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;a href=&quot;https://github.com/angular/angular/releases/tag/20.2.0&quot;&gt;
    &lt;img class=&quot;img-fluid&quot; style=&quot;max-width: 60%;&quot; src=&quot;/assets/images/angular_gradient.webp&quot; alt=&quot;Angular logo&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;


&lt;p&gt;This release marks a pivotal moment for the framework:
the stabilization of Zoneless change detection!
v20.2 also introduces a complete overhaul of the animations API,
and new AI features.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s dive in.&lt;/p&gt;
&lt;h2&gt;Zoneless is stable!&lt;/h2&gt;
&lt;p&gt;Angular&amp;nbsp;v20.2 marks the stability of the Zoneless API (&lt;code&gt;provideZonelessChangeDetection()&lt;/code&gt;),
which allows developers to build Angular applications without the need for zone.js.
New applications are not zoneless by default yet, but this should be the case in the next major version.&lt;/p&gt;
&lt;h2&gt;New animations support&lt;/h2&gt;
&lt;p&gt;This version marks a significant turning point for animations in the framework.
&lt;code&gt;@angular/animations&lt;/code&gt; is now &lt;strong&gt;deprecated and replaced with a new, simpler, API&lt;/strong&gt;.
The animations package hasn&amp;#39;t seen major updates since its original author left the Angular team a few years ago,
and it&amp;#39;s not been actively maintained since then.
The old API was a bit complex, heavy, and built in a time where browsers did not have advanced CSS features.
Most animations can now be written using pure CSS.&lt;/p&gt;
&lt;p&gt;A &lt;a href=&quot;https://github.com/angular/angular/discussions/62212&quot;&gt;RFC&lt;/a&gt; has been opened last June
to discuss the use-cases where pure CSS is not enough.
As a result, Angular&amp;nbsp;20.2 introduces a new (stable) API for animations to handle these cases.&lt;/p&gt;
&lt;p&gt;The problem is that what we often want is to apply a transition effect
when an element appears in the DOM or disappears from the DOM.
But &lt;code&gt;@if&lt;/code&gt; and &lt;code&gt;@for&lt;/code&gt; don’t change the style of an element:
they simply add or remove elements from the DOM.
So we need something more to, for example,
have fade-in and fade-out transitions when elements appear and disappear.&lt;/p&gt;
&lt;p&gt;Angular lets you animate elements with the &lt;code&gt;animate.enter&lt;/code&gt;/&lt;code&gt;animate.leave&lt;/code&gt; syntax,
introduced in v20.2, allowing you to add classes to an element when it enters or leaves the DOM.
These classes are then removed by Angular when the associated animation is done.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;display&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; animate.enter&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;fade-in&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; animate.leave&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;fade-out&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Content&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So here the animated classes are going to be fade-in and fade-out.
Let’s define a &amp;quot;fading&amp;quot; effect in CSS using these classes:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;fade-in&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  /* initial state */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  @starting-style {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B2CCD6&quot;&gt;    opacity&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  transition: opacity 300ms;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  opacity: 1;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;fade-out&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B2CCD6&quot;&gt;  transition&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; opacity &lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;300ms&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B2CCD6&quot;&gt;  opacity&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here the transition will last one second,
and will progressively change the opacity from 0 to 1 when the element enters,
and from 1 to 0 when it leaves.&lt;/p&gt;
&lt;p&gt;Every time the condition of the &lt;code&gt;@if&lt;/code&gt; changes,
the element fades in or fades out over a second,
instead of appearing or disappearing brutally.&lt;/p&gt;
&lt;p&gt;Your imagination (and CSS skills) is the limit here:
you can apply whatever effect you want!&lt;/p&gt;
&lt;p&gt;You can use bindings with &lt;code&gt;animate.enter&lt;/code&gt; and &lt;code&gt;animate.leave&lt;/code&gt;,
to bind a signal value, a method result or an array of classes for example:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;display&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [animate.enter]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;enterClasses()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Content&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you don’t want to rely on CSS animations and prefer to use JavaScript animations,
with the power of libraries like &lt;a href=&quot;https://gsap.com/&quot;&gt;GSAP&lt;/a&gt;,
then you can use &lt;code&gt;animate.enter&lt;/code&gt; and &lt;code&gt;animate.leave&lt;/code&gt;
with the event binding syntax to call a method when the element enters or leaves:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;display&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; (animate.leave)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;rotate($event)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Content&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The method is called with an &lt;code&gt;AnimationCallbackEvent&lt;/code&gt; parameter,
containing the &lt;code&gt;target&lt;/code&gt; that is entering or leaving
and a &lt;code&gt;completeAnimation&lt;/code&gt; method that you must call when the animation is done:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;protected &lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;rotate&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(event: AnimationCallbackEvent) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  gsap&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;to&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    rotation&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 360&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    duration&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 0.3&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    onComplete&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;      event&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;animationComplete&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In tests, the animations are turned off by default, so you don’t have to worry about them.
If you want to test animations,
you can configure the &lt;code&gt;TestBed&lt;/code&gt; to enable animations with the &lt;code&gt;animationsEnabled&lt;/code&gt; option:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;TestBed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;configureTestingModule&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  animationsEnabled&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this option enabled, elements won’t be removed until the animations are done.&lt;/p&gt;
&lt;p&gt;You can check out the new chapter in our &lt;a href=&quot;https://books.ninja-squad.com&quot;&gt;ebook&lt;/a&gt; on animations to learn more.&lt;/p&gt;
&lt;h2&gt;Templates&lt;/h2&gt;
&lt;h2&gt;ARIA bindings&lt;/h2&gt;
&lt;p&gt;If you care about accessibility,
you know how important ARIA (Accessible Rich Internet Applications) attributes are.
Angular&amp;nbsp;v20.2 introduces a new feature to make working with ARIA attributes easier and more intuitive.
Until now, we had to use the &lt;code&gt;attr.&lt;/code&gt; prefix to bind ARIA attributes, like this:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;progressbar&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [attr.aria-valuenow]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;value()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the new feature, you can now bind ARIA attributes directly without the &lt;code&gt;attr.&lt;/code&gt; prefix:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;progressbar&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [aria-valuenow]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;value()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or even:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;progressbar&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [ariaValueNow]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;value()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Angular will automatically set the proper ARIA attributes instead of looking for aria properties.&lt;/p&gt;
&lt;h3&gt;Alias in &lt;code&gt;@else if&lt;/code&gt; blocks&lt;/h3&gt;
&lt;p&gt;The control flow syntax now allows defining an alias in &lt;code&gt;@else if&lt;/code&gt; blocks.
Until now, it was only possible to use &lt;code&gt;as&lt;/code&gt; in the first &lt;code&gt;@if&lt;/code&gt; block,
but now you can also use it in &lt;code&gt;@else if&lt;/code&gt; blocks as well:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;admin&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; a&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  Welcome Admin &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; a&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; @else if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; u&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  Welcome &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; u&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;New characters allowed in templates&lt;/h3&gt;
&lt;p&gt;When the control flow syntax was introduced in Angular&amp;nbsp;v17, it was not possible to use the &lt;code&gt;@&lt;/code&gt; character in templates.
For example to display a user&amp;#39;s email address, you had to use the &lt;code&gt;user&amp;amp;#64;mail.com&lt;/code&gt; property instead of &lt;code&gt;user@mail.com&lt;/code&gt;.
This is no longer the case in Angular&amp;nbsp;20.2,
and you can now use the &lt;code&gt;@&lt;/code&gt; character directly in templates.
The &lt;code&gt;{&lt;/code&gt; and &lt;code&gt;}&lt;/code&gt; characters are still not allowed,
so you still have to use the &lt;code&gt;&amp;amp;#123;&lt;/code&gt; and &lt;code&gt;&amp;amp;#125;&lt;/code&gt; in that case.&lt;/p&gt;
&lt;p&gt;The compiler also accepts more characters in the property binding syntax,
so you can have &lt;code&gt;/&lt;/code&gt; or other &lt;code&gt;[ ]&lt;/code&gt; characters in your property names.
This is mainly to accommodate Tailwind CSS users,
who can have classes with these characters.
The compiler will now correctly parse bindings like &lt;code&gt;[class.text-primary/80]&lt;/code&gt; and &lt;code&gt;[class.data-[size=&amp;#39;large&amp;#39;]]&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Extended diagnostics&lt;/h3&gt;
&lt;p&gt;A new extended diagnostic &lt;code&gt;uninvokedFunctionInTextInterpolation&lt;/code&gt;
has been added to warn you when you forget to call a method in an interpolation.&lt;/p&gt;
&lt;p&gt;For example, if you have a &lt;code&gt;getUserName()&lt;/code&gt; method that returns the user&amp;#39;s name,
and used it in a template like this:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; getUserName &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;throws:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[ERROR] NG8117: Function in text interpolation should be invoked: getUserName().&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Forms&lt;/h2&gt;
&lt;p&gt;It is now possible to push an array of form controls into a FormArray using the &lt;code&gt;push&lt;/code&gt; method.
Until now you had to push them one by one.&lt;/p&gt;
&lt;h2&gt;Router&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;Router.getCurrentNavigation&lt;/code&gt; method has been deprecated and replaced with &lt;code&gt;currentNavigation&lt;/code&gt; signal.
The signal returns the same thing as the previous method, a &lt;code&gt;Navigation&lt;/code&gt; object or null.
A migration has been provided to automatically update your code when running &lt;code&gt;ng update&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Performances&lt;/h2&gt;
&lt;p&gt;The internal algorithm for signals has been changed to use linked lists instead of arrays,
as Preact, Vue and other libraries have done.
This should improve performance, and maybe put the Angular implementation slightly higher in the
&lt;a href=&quot;https://github.com/transitive-bullshit/js-reactivity-benchmark&quot;&gt;reactivity benchmarks&lt;/a&gt; (where it currently ranks dead last).&lt;/p&gt;
&lt;h2&gt;Testing&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;TestBed.createComponent&lt;/code&gt; and &lt;code&gt;TestBed.configureTestingModule&lt;/code&gt; methods have a new option &lt;code&gt;inferTagName&lt;/code&gt;.
When &lt;code&gt;inferTagName&lt;/code&gt; is set to &lt;code&gt;true&lt;/code&gt;,
the &lt;code&gt;TestBed&lt;/code&gt; will automatically infer the tag name of the component being tested based on its selector
and use this tag name in the generated DOM.
Until now (or when the option is &lt;code&gt;false&lt;/code&gt;, as it is by default),
the &lt;code&gt;TestBed&lt;/code&gt; would use a &lt;code&gt;div&lt;/code&gt; to represent the component, which is different from what would happen at runtime.
This is usually not a problem, but the plan is to switch this option to &lt;code&gt;true&lt;/code&gt; by default in a future version
to limit the discrepancies between the test and runtime environments.&lt;/p&gt;
&lt;h2&gt;Service worker&lt;/h2&gt;
&lt;p&gt;The Service Worker package has received several improvements in v20.2,
focusing on better error handling and developer experience.&lt;/p&gt;
&lt;p&gt;Angular now provides better error handling with the addition of &lt;code&gt;messageerror&lt;/code&gt; event handling and logging.
This enhancement allows developers to capture and debug communication errors
between the service worker and the main application thread more effectively.&lt;/p&gt;
&lt;p&gt;The service worker has also gained improved storage management
with better detection of storage full scenarios when caching data.
This prevents silent failures and provides clearer feedback
when 95% of the browser&amp;#39;s storage quota is reached during data caching operations.&lt;/p&gt;
&lt;p&gt;A new &lt;code&gt;updateViaCache&lt;/code&gt; option is now supported in &lt;code&gt;provideServiceWorker()&lt;/code&gt;,
giving developers more control over how the service worker updates itself.
This option allows you to specify whether the service worker script
should bypass the browser cache when checking for updates,
which can be set to &lt;code&gt;&amp;#39;all&amp;#39;&lt;/code&gt;, &lt;code&gt;&amp;#39;none&amp;#39;&lt;/code&gt;, or &lt;code&gt;&amp;#39;imports&amp;#39;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Another option, &lt;code&gt;type&lt;/code&gt;,
allows you to specify the type of the ServiceWorker script to register(&lt;code&gt;&amp;#39;classic&amp;#39;&lt;/code&gt; or &lt;code&gt;&amp;#39;module&amp;#39;&lt;/code&gt;, defaults to &lt;code&gt;&amp;#39;classic&amp;#39;&lt;/code&gt;).
When specifying &lt;code&gt;&amp;#39;module&amp;#39;&lt;/code&gt;, it registers the script as an ES module
and allows use of &lt;code&gt;import&lt;/code&gt;/&lt;code&gt;export&lt;/code&gt; syntax and module features.&lt;/p&gt;
&lt;p&gt;Finally, the service worker now notifies clients about version failures with more detailed error information.
When a service worker update fails,
clients now receive &lt;code&gt;VERSION_FAILED&lt;/code&gt; events that include specific error details,
making it easier to debug deployment issues and understand why a service worker update didn&amp;#39;t succeed.&lt;/p&gt;
&lt;p&gt;These improvements enhance the reliability and debuggability of Angular&amp;#39;s service worker implementation,
making it easier for developers to diagnose and resolve issues in production applications.&lt;/p&gt;
&lt;h2&gt;TypeScript 5.9 support&lt;/h2&gt;
&lt;p&gt;Angular&amp;nbsp;v20.2 now supports TypeScript 5.9.
This means you&amp;#39;ll be able to use the latest version of TypeScript in your Angular applications.
You can check out the &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-9/&quot;&gt;TypeScript 5.9 release notes&lt;/a&gt;
to learn more about the new features.&lt;/p&gt;
&lt;h2&gt;Devtools&lt;/h2&gt;
&lt;p&gt;A new tab in the devtools allows to see the &amp;quot;transfer state&amp;quot; of your application
if you use hydration.&lt;/p&gt;
&lt;h2&gt;Angular CLI&lt;/h2&gt;
&lt;h3&gt;Vitest support&lt;/h3&gt;
&lt;p&gt;The experimental &lt;code&gt;unit-test&lt;/code&gt; builder introduced in &lt;a href=&quot;/2025/05/28/what-is-new-angular-20.0/&quot;&gt;Angular&amp;nbsp;v20&lt;/a&gt; has been improved
and now supports the headless mode for Vitest, which means that you can run your tests in a headless browser.
To do so, you need to use the browser mode of the builder
and add the &amp;quot;Headless&amp;quot; suffix to the browser name, like this:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;runner&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;vitest&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;browsers&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ChromiumHeadless&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Rolldown chunk optimization&lt;/h3&gt;
&lt;p&gt;The experimental chunk optimization that has been around since
&lt;a href=&quot;/2024/07/10/what-is-new-angular-18.1/&quot;&gt;Angular&amp;nbsp;v18.1&lt;/a&gt; now uses &lt;a href=&quot;https://rolldown.rs/&quot;&gt;rolldown&lt;/a&gt; instead of rollup.
Rolldown is a new tool, compatible with rollup, but written in Rust, which makes it faster.
It is developed by the VoidZero team, the same team that now develops &lt;a href=&quot;https://vitejs.dev/&quot;&gt;Vite&lt;/a&gt;.
Rolldown is still experimental and less battle-tested than rollup, but as the chunk optimization option is itself experimental,
I guess this is not a big deal, and we may see a tiny performance improvement in build times.&lt;/p&gt;
&lt;h3&gt;AI&lt;/h3&gt;
&lt;p&gt;A large part of the new features of the CLI are in the AI domain.&lt;/p&gt;
&lt;p&gt;A new command lets you generate configuration files for your favorites AI tools:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ng&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; g&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; ai-config&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; --tool=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;your-favorite-ai-tool&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The supported tools are &lt;code&gt;gemini&lt;/code&gt;, &lt;code&gt;claude&lt;/code&gt;, &lt;code&gt;copilot&lt;/code&gt;, &lt;code&gt;windsurf&lt;/code&gt;, &lt;code&gt;jetbrains&lt;/code&gt;, and &lt;code&gt;cursor&lt;/code&gt;.
For example &lt;code&gt;--tool=claude&lt;/code&gt; generates a &lt;code&gt;.claude/CLAUDE.md&lt;/code&gt; file in the directory containing the Angular best practices.
&lt;code&gt;ng new&lt;/code&gt; will also prompt for the AI tool to use when generating a new project.&lt;/p&gt;
&lt;p&gt;The MCP server introduced in &lt;a href=&quot;/2025/07/09/what-is-new-angular-20.1/&quot;&gt;Angular&amp;nbsp;v20.1&lt;/a&gt; gained a few new features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a &lt;code&gt;search_documentation&lt;/code&gt; tool has been added to search the documentation from the CLI, using the same search engine (Algolia) as the documentation website. The LLM will use this if asked a question about Angular and return a list of entries with their titles and URLs,
with the top entry directly fetched and displayed;&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;get_best_practices&lt;/code&gt; tool, similar to the existing resource, in case resources are not available in your LLM;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;mcp&lt;/code&gt; command now also accepts options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--local-only&lt;/code&gt; indicates to only use local tools (no network access, so the search_documentation is not available)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--read-only&lt;/code&gt; indicates to only use read-only tools (no write access, but for the moment all tools are read-only)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--experimental-tool &amp;lt;tool&amp;gt;&lt;/code&gt; indicates to use an experimental tool&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Two new experimental tool have been added, and can be enabled with &lt;code&gt;--experimental-tool&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a &lt;code&gt;modernize&lt;/code&gt; tool, which helps you generate code or update your files to use the latest best practices and features. When used, it will tell the LLM which migration can be run and the LLM can determine which ones are useful and can then prompt you to run the migration. The current migrations listed are &lt;code&gt;control-flow&lt;/code&gt;, &lt;code&gt;self-closing-tags&lt;/code&gt;, &lt;code&gt;inject&lt;/code&gt;, &lt;code&gt;standalone&lt;/code&gt;, and the signal migrations (&lt;code&gt;input&lt;/code&gt;, &lt;code&gt;output&lt;/code&gt;, &lt;code&gt;queries&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;find_examples&lt;/code&gt; tool, which helps the LLM to generate code by using a pool of examples. Only one simple example is available for now (a simple &lt;code&gt;@if&lt;/code&gt;) but the feature allows to register your own examples in a directory, and then use the &lt;code&gt;NG_MCP_EXAMPLES_DIR&lt;/code&gt; environment variable to let the MCP know about the location of the examples.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This next release will be v21, and will hopefully include signal forms.
Stay tuned!&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>What&apos;s new in Angular 20.1?</title>
    <link href="https://blog.ninja-squad.com/2025/07/09/what-is-new-angular-20.1"/>
    <updated>2025-07-09T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2025/07/09/what-is-new-angular-20.1</id>
    <content type="html">
      &lt;p&gt;Angular&amp;nbsp;20.1.0 is here!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;a href=&quot;https://github.com/angular/angular/releases/tag/20.1.0&quot;&gt;
    &lt;img class=&quot;img-fluid&quot; style=&quot;max-width: 60%;&quot; src=&quot;/assets/images/angular_gradient.webp&quot; alt=&quot;Angular logo&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;One month after the huge v20 release,
the Angular team delivers a new minor update.
This release introduces devtools with signal dependency graphs,
improvements in component testing with new binding helpers,
and adds a lot of HTTP client options that can boost your Core Web Vitals scores.
Plus, Angular takes its first steps into the AI-assisted development era with MCP server support.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s dive in.&lt;/p&gt;
&lt;h2&gt;Devtools&lt;/h2&gt;
&lt;p&gt;The devtools have been updated with some nice new features.
You can now inspect the details of a route in the router tab,
but most of the improvements are for signals.&lt;/p&gt;
&lt;p&gt;We can now inspect a signal from the devtools and jump to its definition.
But more importantly,
we now have a new &amp;quot;Signal Graph&amp;quot; tab
that shows the dependencies between signals in a graph,
and flashing of nodes when a signal changes.
It can be enabled in the devtools settings
by switching on the &amp;quot;Enable signal graph (experimental)&amp;quot; option.
You can then click on a component and on the &amp;quot;Show signal graph&amp;quot; button
to see the graph of signals that are used in this component!&lt;/p&gt;
&lt;p&gt;You then get a (still a bit rough) graph with signals and inputs in blue,
computed signals in green, and effects in grey.
It will probably be improved in the future,
but it is already a nice way to visualize the dependencies between signals
and to understand how they are used in your application.
Some compiler magic (a TypeScript transformer) has been implemented to add a &amp;quot;debugName&amp;quot; to each signal,
based on the variable name in the component,
which is used in the graph to display the name of the signal.&lt;/p&gt;
&lt;h2&gt;Tests&lt;/h2&gt;
&lt;p&gt;It is now possible to create a component in a test with its bindings directly set.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s say you have a &lt;code&gt;User&lt;/code&gt; component:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; User&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  readonly&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; userModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;UserModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  readonly&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; selected&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; output&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A common practice is to test this type of component with a wrapper component:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; `&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;app-user&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;    [userModel]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;userModel()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;    (selected)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;isSelected.set(true)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  /&gt;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; UserHost&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  readonly&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; userModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; signal&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;UserModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    /* ... */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  readonly&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; isSelected&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; signal&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;it&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;should display a user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; fixture&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; TestBed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;createComponent&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;UserHost&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // ....&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can now be simplified,
thanks to &lt;code&gt;inputBinding()&lt;/code&gt;, &lt;code&gt;outputBinding()&lt;/code&gt; and &lt;code&gt;twoWayBinding()&lt;/code&gt; that were
&lt;a href=&quot;/2025/05/28/what-is-new-angular-20.0/&quot;&gt;introduced in v20&lt;/a&gt;
and to an evolution of the &lt;code&gt;TestBed.createComponent&lt;/code&gt; method in v20.1:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;it&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;should display a user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; userModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; signal&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;UserModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    /* ... */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; isSelected&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; signal&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; fixture&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; TestBed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;createComponent&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // 👇 directly bind inputs/outputs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    bindings&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;      inputBinding&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;userModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; userModel&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;      outputBinding&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;selected&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; isSelected&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    ]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // ....&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a nice improvement, even if the &amp;quot;wrapper component&amp;quot; approach
is still valid and can be useful in some cases, for example,
 when you want to test a component 
 which uses &lt;code&gt;ng-content&lt;/code&gt; or a directive that requires a host element.&lt;/p&gt;
&lt;h2&gt;Performances&lt;/h2&gt;
&lt;p&gt;The low-level set of instructions that the compiler generates for templates
has been extended with DOM-only instructions,
used when the compiler can safely determine that the element has no directives applied to it.
Those DOM-only instructions are more efficient than the generic ones,
even if this is hard to measure in practice.&lt;/p&gt;
&lt;p&gt;A template like the following:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;figure&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;img&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [src]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;userImageUrl()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;figcaption&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; userModel&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;figcaption&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;figure&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;used to be compiled into the following instructions:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (renderFlags &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; RenderFlags&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Create) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  elementStart&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;figure&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    element&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;img&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    elementStart&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;figcaption&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    text&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    elementEnd&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  elementEnd&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (renderFlags &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; RenderFlags&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Update) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  advance&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  property&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; ctx&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;userImageUrl&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  advance&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  textInterpolate&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;ctx&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;userModel&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is now compiled into the following instructions:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (renderFlags &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; RenderFlags&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Create) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  domElementStart&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;figure&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    domElement&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;img&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    domElementStart&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;figcaption&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    text&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    domElementEnd&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  domElementEnd&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (renderFlags &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; RenderFlags&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Update) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  advance&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  domProperty&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; ctx&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;userImageUrl&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  advance&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  textInterpolate&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;ctx&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;userModel&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;elementStart&lt;/code&gt;, &lt;code&gt;element&lt;/code&gt;, &lt;code&gt;elementEnd&lt;/code&gt;,
and &lt;code&gt;property&lt;/code&gt; instructions still exist,
but they are now used only when the component has dependencies.&lt;/p&gt;
&lt;h2&gt;Templates&lt;/h2&gt;
&lt;p&gt;The compiler now supports assignment operators in templates:
&lt;code&gt;+=&lt;/code&gt;, &lt;code&gt;-=&lt;/code&gt;, &lt;code&gt;*=&lt;/code&gt;, &lt;code&gt;/=&lt;/code&gt;, &lt;code&gt;%=&lt;/code&gt;, &lt;code&gt;**=&lt;/code&gt;, &lt;code&gt;&amp;amp;&amp;amp;=&lt;/code&gt;, &lt;code&gt;||=&lt;/code&gt; and &lt;code&gt;??=&lt;/code&gt; are now allowed.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;NgOptimizedImage&lt;/code&gt; directive now offers a &lt;code&gt;decoding&lt;/code&gt; option,
which can be set to &lt;code&gt;async&lt;/code&gt;, &lt;code&gt;sync&lt;/code&gt;, or &lt;code&gt;auto&lt;/code&gt; (default).
You can use &lt;code&gt;async&lt;/code&gt; to decode the image off the main thread,
or &lt;code&gt;sync&lt;/code&gt; to decode it immediately (blocking).
&lt;code&gt;auto&lt;/code&gt; lets the browser decide the best strategy.&lt;/p&gt;
&lt;h2&gt;HTTP&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;HttpClient&lt;/code&gt; gained a bunch of new options in v20.1:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;timeout&lt;/code&gt; which indicates the maximum time to wait for a response.
It can be set to a number of milliseconds.
If the request takes longer than this time, it will be aborted.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cache&lt;/code&gt; (with the Fetch API only) which indicates if the request should use the browser cache.
It can be set to &lt;code&gt;default&lt;/code&gt;, &lt;code&gt;no-store&lt;/code&gt;, &lt;code&gt;reload&lt;/code&gt;, &lt;code&gt;no-cache&lt;/code&gt;, &lt;code&gt;force-cache&lt;/code&gt; or &lt;code&gt;only-if-cached&lt;/code&gt;,
see &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Request/cache&quot;&gt;MDN&lt;/a&gt; for more details.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;priority&lt;/code&gt; (with the Fetch API only) which indicates the priority of the request.
It can be set to &lt;code&gt;auto&lt;/code&gt; (default), &lt;code&gt;high&lt;/code&gt; or &lt;code&gt;low&lt;/code&gt;.
It can be useful to improve your Core Web Vitals scores
by distinguishing between high-priority requests that impact LCP and low-priority requests.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mode&lt;/code&gt; (with the Fetch API only) which indicates the mode of the request.
It can be set to &lt;code&gt;cors&lt;/code&gt; (default), &lt;code&gt;no-cors&lt;/code&gt;, &lt;code&gt;same-origin&lt;/code&gt; or &lt;code&gt;navigate&lt;/code&gt;.
This is used to determine if cross-origin requests lead to valid responses,
and which properties of the response are readable, see &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Request/mode&quot;&gt;MDN&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;redirect&lt;/code&gt; (with the Fetch API only) which indicates how to handle redirects.
It can be set to &lt;code&gt;follow&lt;/code&gt; (default), &lt;code&gt;error&lt;/code&gt; or &lt;code&gt;manual&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;credentials&lt;/code&gt; (with the Fetch API only) which indicates whether to include credentials in the request.
It can be set to &lt;code&gt;omit&lt;/code&gt; (default), &lt;code&gt;same-origin&lt;/code&gt; or &lt;code&gt;include&lt;/code&gt;.
This is used to determine if cookies and HTTP authentication are included in the request,
see &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials&quot;&gt;MDN&lt;/a&gt;.
This option is more flexible than the existing &lt;code&gt;withCredentials&lt;/code&gt; option
(which is still available and is equivalent to &lt;code&gt;include&lt;/code&gt;) and should be preferred.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;referrer&lt;/code&gt; (with the Fetch API only) which indicates the referrer of the request.
It can be set to a URL, an empty string for no referrer or &lt;code&gt;about:client&lt;/code&gt;.
This is used to determine the referrer of the request,
see &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Request/referrer&quot;&gt;MDN&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;integrity&lt;/code&gt; (with the Fetch API only) which indicates the integrity of the request.
It can be set to a hash of the response body.
This is used to verify that the response has not been tampered with,
see &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Request/integrity&quot;&gt;MDN&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most of these options are not supported when using the XHR backend.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;HttpResource&lt;/code&gt; also supports all these options
as well as &lt;code&gt;keepalive&lt;/code&gt; (introduced in v20 for the &lt;code&gt;HttpClient&lt;/code&gt;).&lt;/p&gt;
&lt;h2&gt;Router&lt;/h2&gt;
&lt;p&gt;The router &lt;code&gt;loadChildren&lt;/code&gt; and &lt;code&gt;loadComponent&lt;/code&gt; functions now run
in the injection context of the route,
allowing you to inject services within the functions.&lt;/p&gt;
&lt;h2&gt;Service worker&lt;/h2&gt;
&lt;p&gt;The Service Worker Push service &lt;code&gt;SwPush&lt;/code&gt; now supports the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/notificationclose_event&quot;&gt;&lt;code&gt;notificationclose&lt;/code&gt;&lt;/a&gt; and the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/pushsubscriptionchange_event&quot;&gt;&lt;code&gt;pushsubscriptionchange&lt;/code&gt;&lt;/a&gt; events,
with the new &lt;code&gt;notificationCloses&lt;/code&gt; and &lt;code&gt;pushSubscriptionChanges&lt;/code&gt; observables (in addition of the existing &lt;code&gt;notificationClicks&lt;/code&gt; observable).&lt;/p&gt;
&lt;h2&gt;Angular CLI&lt;/h2&gt;
&lt;p&gt;This is a fairly small release for the CLI.&lt;/p&gt;
&lt;p&gt;A notable feature is the possibility to use &lt;code&gt;base64&lt;/code&gt; and &lt;code&gt;dataurl&lt;/code&gt; loaders,
in addition to the pre-existing &lt;code&gt;text&lt;/code&gt;, &lt;code&gt;binary&lt;/code&gt;, and &lt;code&gt;file&lt;/code&gt; loaders.
&lt;code&gt;dataurl&lt;/code&gt; inlines the content as a data URL
and &lt;code&gt;base64&lt;/code&gt; inlines the content as a Base64-encoded string.&lt;/p&gt;
&lt;p&gt;This can be used to inline small assets in your application:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; contents &lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;./assets/small-image.png&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; with&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; loader&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;dataurl&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; };&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The experimental unit-test builder now allows to define some options (only for vitest):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;setupFiles&lt;/code&gt; which are files that are loaded before the tests are run,
allowing you to set up the test environment.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;codeCoverageReporters&lt;/code&gt; which allows you to specify the code coverage reporters to use.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But the main feature of CLI v20.1 is the new &lt;code&gt;ng mcp&lt;/code&gt; command,
which allows you to start an MCP server,
a hot topic in the AI community.&lt;/p&gt;
&lt;p&gt;So let&amp;#39;s talk about AI!&lt;/p&gt;
&lt;h2&gt;AI&lt;/h2&gt;
&lt;p&gt;Angular is fully embracing the AI trend.
We now have a new documentation page explaining how to properly configure your favorite AI tool to help you with Angular development:
&lt;a href=&quot;https://angular.dev/ai/develop-with-ai&quot;&gt;Develop with AI&lt;/a&gt;.
The page provides rules files for the most popular AI tools, such as Copilot, Cursor, VSCode, etc.&lt;/p&gt;
&lt;p&gt;The CLI has also been updated and now includes an MCP server.
MCP stands for &amp;quot;Model Control Protocol&amp;quot;
and is the hot new protocol that allows LLMs to communicate with external tools and resources.
This protocol was introduced by Anthropic last year and is now supported by many AI tools.&lt;/p&gt;
&lt;p&gt;You can run:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ng&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; mcp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which outputs the configuration you need to add to your AI tool:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;To start using the Angular CLI MCP Server, add this configuration to your host:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;mcpServers&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;angular-cli&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &quot;command&quot;: &quot;npx&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &quot;args&quot;: [&quot;@angular/cli&quot;, &quot;mcp&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Exact configuration may differ depending on the host.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This means that you can now use the CLI to start an MCP server,
then configure your favorite AI tool to connect to it.
The MCP server is quite minimalist for now,
as it offers only one resource (the best practice file mentioned above)
and one tool (the ability to list the Angular projects and their options in your workspace).&lt;/p&gt;
&lt;p&gt;In my experiment with Copilot and Claude Code,
it seems that extending the context with the resources the MCP server provides
does make a difference in the quality of the suggestions.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;Most features of v20.1 are oriented towards improving the developer experience.
We also saw a new RFC about &lt;a href=&quot;https://github.com/angular/angular/discussions/62212&quot;&gt;the future of the animation package&lt;/a&gt;.
We can expect movements in this area in the next releases
and hopefully some movements in the signal forms area as well.&lt;/p&gt;
&lt;p&gt;Stay tuned!&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>What&apos;s new in Angular 20.0?</title>
    <link href="https://blog.ninja-squad.com/2025/05/28/what-is-new-angular-20.0"/>
    <updated>2025-05-28T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2025/05/28/what-is-new-angular-20.0</id>
    <content type="html">
      &lt;p&gt;Angular&amp;nbsp;20.0.0 is here!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;a href=&quot;https://github.com/angular/angular/releases/tag/20.0.0&quot;&gt;
    &lt;img class=&quot;img-fluid&quot; style=&quot;max-width: 60%;&quot; src=&quot;/assets/images/angular_gradient.webp&quot; alt=&quot;Angular logo&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;It sounds a bit incredible that we are already at version 20,
but here we are!
This is a major release with a lot of new features,
improvements and breaking changes.
Let&amp;#39;s dive into the details of this new version
and also look at what to expect in Angular v21 👀.&lt;/p&gt;
&lt;h2&gt;TypeScript v5.8 and Node v20 required&lt;/h2&gt;
&lt;p&gt;Angular v20 now requires TypeScript v5.8 (it has been supported since v19.2).
You can check out the &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-8-rc/&quot;&gt;TypeScript v5.8 release notes&lt;/a&gt;
to learn more about the new features.
Older versions of TypeScript are not supported anymore.&lt;/p&gt;
&lt;p&gt;Angular v20 also requires Node v20.
Angular v19 was the last version to support Node v18.&lt;/p&gt;
&lt;h2&gt;2025 Angular style guide&lt;/h2&gt;
&lt;p&gt;A major update of the Angular style guide has been released,
with a lot of recommendations removed to focus on the most important ones.&lt;/p&gt;
&lt;p&gt;You can check it out at &lt;a href=&quot;https://angular.dev/style-guide&quot;&gt;angular.dev/style-guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The recommended naming convention for files has changed,
with most of the suffixes being removed.
A user component should now be named &lt;code&gt;User&lt;/code&gt;,
or &lt;code&gt;UserCard&lt;/code&gt;, or &lt;code&gt;UserPage&lt;/code&gt; (for example) instead of &lt;code&gt;UserComponent&lt;/code&gt;.
in a file named &lt;code&gt;user.ts&lt;/code&gt; (or &lt;code&gt;user-card.ts&lt;/code&gt;, or &lt;code&gt;user-page.ts&lt;/code&gt;)
instead of &lt;code&gt;user.component.ts&lt;/code&gt;.
The same applies to directives, pipes, etc.
The CLI has been updated to use this new naming convention by default,
as explained below.&lt;/p&gt;
&lt;p&gt;The folder structure has also evolved, with the removal of the top-level &lt;code&gt;app&lt;/code&gt; folder.
The CLI does not comply with this new structure yet,
but I imagine it will be the new default soon.&lt;/p&gt;
&lt;p&gt;Among other notable changes,
it is now recommended to use &lt;code&gt;protected&lt;/code&gt; for properties that are only accessed in the template,
and &lt;code&gt;readonly&lt;/code&gt; for all the properties that are initialized by Angular,
like &lt;code&gt;input()&lt;/code&gt;, &lt;code&gt;output()&lt;/code&gt;, etc.&lt;/p&gt;
&lt;p&gt;It is also now official that &lt;code&gt;[class.something]&lt;/code&gt; and &lt;code&gt;[style.something]&lt;/code&gt;
are the recommended way to bind classes and styles in templates over &lt;code&gt;ngClass&lt;/code&gt; and &lt;code&gt;ngStyle&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This new naming convention and style guide
is a big change for Angular,
and even if new projects will use it by default,
existing projects will either have to migrate to it
or keep using the old style guide (see the CLI section below for more details).&lt;/p&gt;
&lt;h2&gt;Signal APIs are stable&lt;/h2&gt;
&lt;p&gt;Signals are the future of Angular reactivity,
and the Angular team has been working hard to stabilize the APIs around them.&lt;/p&gt;
&lt;p&gt;Most of the APIs related to signals are now stable:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;effect()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;toSignal()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;toObservable()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;afterRenderEffect()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;afterNextRender()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;linkedSignal()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PendingTasks&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Two developer preview APIs are being renamed.&lt;/p&gt;
&lt;p&gt;The biggest change is that &lt;code&gt;afterRender()&lt;/code&gt; has been renamed to &lt;code&gt;afterEveryRender()&lt;/code&gt;
and is now stable.
Unlike stable APIs, the old name wasn&amp;#39;t kept for backward compatibility,
and no migration was provided.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;TestBed.flushEffects()&lt;/code&gt;,
which was introduced in v17 to trigger pending effects in tests,
has been deprecated and should now be replaced with &lt;code&gt;TestBed.tick()&lt;/code&gt;.
This new method runs the entire synchronization process instead of
manually triggering the effects in a way that would not happen in a running application.
&lt;code&gt;flushEffects&lt;/code&gt; had a special treatment and was kept around as deprecated
because it was not visible on the docs that it was in developer preview 🤷.&lt;/p&gt;
&lt;p&gt;Note that &lt;code&gt;effect()&lt;/code&gt; lost its &lt;code&gt;forceRoot&lt;/code&gt; option, which was not very useful,
and &lt;code&gt;toSignal()&lt;/code&gt; lost its &lt;code&gt;rejectErrors&lt;/code&gt; option, which was deemed a not-so-good practice.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pendingUntilEvent()&lt;/code&gt;, the RxJS operator &lt;a href=&quot;/2024/11/19/what-is-new-angular-19.0/&quot;&gt;introduced in v19&lt;/a&gt;, has been promoted from experimental to developer preview.&lt;/p&gt;
&lt;h2&gt;Zoneless is now in developer preview&lt;/h2&gt;
&lt;p&gt;If signals are the future of Angular reactivity,
zoneless change detection is the future of Angular change detection.&lt;/p&gt;
&lt;p&gt;Zoneless is no longer experimental, but not yet stable.
It is now in developer preview and, to reflect that,
the provider has been renamed from &lt;code&gt;provideExperimentalZonelessChangeDetection&lt;/code&gt;
to &lt;code&gt;provideZonelessChangeDetection&lt;/code&gt;.
Similarly, &lt;code&gt;provideExperimentalCheckNoChangesForDebug&lt;/code&gt; has been renamed to &lt;code&gt;provideCheckNoChangesForDebug&lt;/code&gt;
(check &lt;a href=&quot;/2024/05/22/what-is-new-angular-18.0/&quot;&gt;our article about Angular v18 to learn more about these providers&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;ng new --experimental-zoneless&lt;/code&gt; flag has also been renamed to &lt;code&gt;--zoneless&lt;/code&gt; in the CLI
and the CLI now asks if you want to enable it when creating a new project.&lt;/p&gt;
&lt;h2&gt;Deprecations, removals and breaking changes&lt;/h2&gt;
&lt;p&gt;As usual with major releases,
Angular v20 comes with a few deprecations, removals, and breaking changes.&lt;/p&gt;
&lt;p&gt;The structural directives &lt;code&gt;ngIf&lt;/code&gt;, &lt;code&gt;ngFor&lt;/code&gt; and &lt;code&gt;ngSwitch&lt;/code&gt;
are now officially deprecated in favor of the
&lt;a href=&quot;/2023/10/11/angular-control-flow-syntax/&quot;&gt;control flow syntax&lt;/a&gt;.
Note that structural directives in general are not deprecated,
but only the &lt;code&gt;ngIf&lt;/code&gt;, &lt;code&gt;ngFor&lt;/code&gt;, and &lt;code&gt;ngSwitch&lt;/code&gt; ones.
These directives will likely be removed in Angular v22.
The control flow migration can help you migrate
and you will be asked if you want to run it during &lt;code&gt;ng update&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;fixture.autoDetectChanges()&lt;/code&gt; method previously accepted a boolean parameter,
now deprecated due to limited utility.
If you used &lt;code&gt;fixture.autoDetectChanges(true)&lt;/code&gt;,
you can now just use &lt;code&gt;fixture.autoDetectChanges()&lt;/code&gt;.
&lt;code&gt;fixture.autoDetectChanges(false)&lt;/code&gt; is now even throwing if used in a zoneless test.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;TestBed.get()&lt;/code&gt; has finally been removed
(it had been deprecated in Angular v9).
An automatic migration will run when you &lt;code&gt;ng update&lt;/code&gt;
to replace these calls with &lt;code&gt;TestBed.inject()&lt;/code&gt; if you still have some.&lt;/p&gt;
&lt;p&gt;Probably not much used, but worth noting,
the &lt;code&gt;InjectFlags&lt;/code&gt; enum is also removed.
As explained in our &lt;a href=&quot;/2022/07/21/what-is-new-angular-14.1/&quot;&gt;Angular v14.1 blog post&lt;/a&gt;,
these flags were deprecated in v14.1
when most of the DI APIs like &lt;code&gt;inject()&lt;/code&gt; started to accept an options object instead.
You probably did not have the time to use it,
but a migration is nonetheless run during &lt;code&gt;ng update&lt;/code&gt;
to take care of it if that was the case.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;DOCUMENT&lt;/code&gt; token moved from &lt;code&gt;@angular/common&lt;/code&gt; to &lt;code&gt;@angular/core&lt;/code&gt;.
Here as well, a migration will rewrite the imports in your project if needed.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;@angular/platform-browser-dynamic&lt;/code&gt; package
has been deprecated in favor of &lt;code&gt;@angular/platform-browser&lt;/code&gt;,
but here you&amp;#39;ll have to manually update the imports as there is no schematics for now.
You can then remove the dependency from your project.&lt;/p&gt;
&lt;p&gt;Another package got deprecated but with no replacement &lt;code&gt;@angular/platform-server/testing&lt;/code&gt;.
It is now recommended to use e2e tests to check your SSR applications.&lt;/p&gt;
&lt;p&gt;The HammerJS integration has been deprecated.
HammerJS has not been updated for the past 8 years
so the team is planning to remove all HammerJS entities
from the framework in the future.&lt;/p&gt;
&lt;p&gt;Another breaking change that may go unnoticed
is the removal of the generated &lt;code&gt;ng-reflect-*&lt;/code&gt; attributes
by default.
These attributes have been present in dev mode since v2.4
for historical debugging reasons (I think the old devtools used them).
If you rely on this in your application, which is a bad idea,
you can re-enable them in dev mode using &lt;code&gt;provideNgReflectAttributes()&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Templates&lt;/h2&gt;
&lt;p&gt;Angular v20 supports a few new things in templates.&lt;/p&gt;
&lt;p&gt;Exponentiation is now supported in templates, using the &lt;code&gt;**&lt;/code&gt; operator.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; **&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Angular v19.2 introduced
&lt;a href=&quot;/2025/02/26/what-is-new-angular-19.2/&quot;&gt;the support for template strings in expressions&lt;/a&gt;,
and we now have the ability to use tagged template literals as well:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; translate&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;app.title&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;void&lt;/code&gt; is now also supported in template expressions.
This can be useful to ignore the return value of a function,
for example for event listeners (as returning &lt;code&gt;false&lt;/code&gt; prevents the default behavior):&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; (click)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;void selectUser()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Select user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;in&lt;/code&gt; is supported as well in v20:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;invoicing&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; permissions) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; routerLink&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;/invoices&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Invoices&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Extended diagnostics&lt;/h2&gt;
&lt;p&gt;As a proof that structural directives are still alive,
a new extended diagnostic has been added to check if
you&amp;#39;re using a structural directive without importing it: &lt;code&gt;missingStructuralDirective&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If that&amp;#39;s the case, you&amp;#39;ll get the &lt;a href=&quot;https://next.angular.dev/extended-diagnostics/NG8116&quot;&gt;following error&lt;/a&gt;
with &lt;code&gt;strictTemplates&lt;/code&gt; enabled if you are using &lt;code&gt;*ngTemplateOutlet&lt;/code&gt; without importing it for example:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[ERROR] NG8116: A structural directive `ngTemplateOutlet` was used in the template without a corresponding import in the component.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Make sure that the directive is included in the `@Component.imports` array of this component.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another extended diagnostic has been added to check that a function is properly invoked when used in a track expression of a &lt;code&gt;@for&lt;/code&gt; block.
For example, &lt;code&gt;@for (user of users; track getUserId) {&lt;/code&gt; throws the following error:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[ERROR] NG8115: The track function in the @for block should be invoked: getUserId(/* arguments */) [plugin angular-compiler]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A last one has been added to check if you are mixing nullish coalescing
with boolean operations in templates.
TypeSCript forces you to use parentheses in this case when using the nullish coalescing operator (&lt;code&gt;??&lt;/code&gt;)
and a boolean operator (&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;, &lt;code&gt;||&lt;/code&gt;, etc.) in the same expression like &lt;code&gt;a ?? b &amp;amp;&amp;amp; c&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In templates, there was no such check before
and it is now recommended to use parentheses to avoid confusion.
You now need to write &lt;code&gt;{{ a ?? (b &amp;amp;&amp;amp; c) }}&lt;/code&gt; instead of &lt;code&gt;{{ a ?? b &amp;amp;&amp;amp; c }}&lt;/code&gt; for example,
otherwise you&amp;#39;ll get the &lt;a href=&quot;https://next.angular.dev/extended-diagnostics/NG8114&quot;&gt;following error&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[ERROR] NG8114: Parentheses are required to disambiguate precedence when mixing &apos;??&apos; with &apos;&amp;#x26;&amp;#x26;&apos; and &apos;||&apos;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To disable these checks, you can add the following to your &lt;code&gt;tsconfig.json&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;angularCompilerOptions&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;extendedDiagnostics&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;checks&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &quot;&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;missingStructuralDirective&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;suppress&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &quot;&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;unparenthesizedNullishCoalescing&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;suppress&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &quot;&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;uninvokedTrackFunction&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;suppress&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Host type checking&lt;/h2&gt;
&lt;p&gt;The type-checking has been improved in an area that was not type-checked before.&lt;/p&gt;
&lt;p&gt;If you ever used the &lt;code&gt;host&lt;/code&gt; metadata in
a directive or component decorator
(or the &lt;code&gt;@HostBinding()&lt;/code&gt; and &lt;code&gt;@HostListener()&lt;/code&gt; decorators),
then you may have noticed this was not checked by the compiler.
This is no longer the case in v20 if you use a new option of the compiler
called &lt;code&gt;typeCheckHostBindings&lt;/code&gt; (this is already configured in new CLI project):&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;angularCompilerOptions&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;typeCheckHostBindings&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; true,&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The compiler now checks that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the left side of the host binding/listener is valid for the element on which the component/directive is applied to&lt;/li&gt;
&lt;li&gt;the right side references something that exists in the component/directive class&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example, the following code errors as &lt;code&gt;value&lt;/code&gt; does not exist on labels:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Directive&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt; selector&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt; host&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;[value]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;value()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // ☝️ [ERROR] NG8002: Can&apos;t bind to &apos;value&apos; since it isn&apos;t a known property of &apos;label&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;export &lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; FormLabel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The type checker is smart enough to understand if the binding works with &lt;em&gt;all&lt;/em&gt;
elements declared in the selector.&lt;/p&gt;
&lt;p&gt;It also checks the right side of the binding to see if it exists.
So the following throws as well:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Directive&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  selector&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  host&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;[class.text-danger]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;isInvalid&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // ☝️ [ERROR] NG9: Property &apos;isInvalid&apos; does not exist on type &apos;FormLabel&apos;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that extended diagnostics are not running on these bindings for now,
so it does not catch if a signal is not called for example.&lt;/p&gt;
&lt;h2&gt;Error handling&lt;/h2&gt;
&lt;p&gt;Some changes have been made
to avoid letting errors slip through the cracks.&lt;/p&gt;
&lt;p&gt;A new &lt;code&gt;provideBrowserGlobalErrorListeners&lt;/code&gt; provider has been added in Angular v20.
It allows to register global error listeners in the browser.
This is useful to catch errors that are not caught by Angular.
This provider is automatically added to the &lt;code&gt;app.config.ts&lt;/code&gt; file
when you create a new project with the CLI.&lt;/p&gt;
&lt;p&gt;Note that the errors thrown in event listeners are now reported
to the internal Angular error handler, which means that
you may see errors in tests that were not reported before.
You can fix them or use &lt;code&gt;rethrowApplicationErrors: false&lt;/code&gt;
in &lt;code&gt;configureTestingModule&lt;/code&gt; as a last resort.&lt;/p&gt;
&lt;h2&gt;Dynamically created components&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;createComponent()&lt;/code&gt; API (&lt;a href=&quot;/2022/08/26/what-is-new-angular-14.2/&quot;&gt;v14.2&lt;/a&gt;)
allows to dynamically create components to manually insert them.&lt;/p&gt;
&lt;p&gt;The function (and &lt;code&gt;ViewViewContainerRef.createComponent&lt;/code&gt;) gained
a few possible options in v20.
You can specify the directives to apply to dynamically created components,
as well as the input values you want to provide to the component (or its applied directives) using the brand new &lt;code&gt;inputBinding()&lt;/code&gt; function.
It is also possible to declare two-way bindings with &lt;code&gt;twoWayBinding()&lt;/code&gt;
and to listen to outputs with ``:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; createComponent&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(User&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  bindings&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    twoWayBinding&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; name)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  ]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // ☝️ two-way binding with the signal `name`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  directives&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      type&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; CdkDrag&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;      // ☝️ applies the Drag directive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      bindings&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;        inputBinding&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;cdkDragLockAxis&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;        // ☝️ binds its lock axis to &apos;x&apos; (has to be a signal or a function)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;        outputBinding&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;CdkDragEnd&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;cdkDragEnded&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; event&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(event))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;        // ☝️ listens to the end of the dragging action&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;      ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a step up from the current &lt;code&gt;setInput&lt;/code&gt; that could be called on the created component,
but that would set the input &lt;em&gt;after&lt;/em&gt; the first change detection.
We can also imagine that this could be used in other APIs like &lt;code&gt;TestBed.createComponent()&lt;/code&gt;
in the future?&lt;/p&gt;
&lt;h2&gt;Forms&lt;/h2&gt;
&lt;p&gt;Still no signal support in the forms APIs,
but the Angular team is working on it.
Check out our sneak peek of the new forms APIs below 😉.&lt;/p&gt;
&lt;p&gt;The forms APIs are relatively quiet in v20,
but we have two minor changes worth mentioning.&lt;/p&gt;
&lt;p&gt;It is now possible to reset forms without emitting events
with &lt;code&gt;userForm.resetForm(undefined, { emitEvent: false })&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We also now have a &lt;code&gt;markAllAsDirty()&lt;/code&gt; method on &lt;code&gt;AbstractControl&lt;/code&gt;,
which allows us to mark a control and all its descendants as dirty.
The &lt;code&gt;markAllAsTouched()&lt;/code&gt; method already existed
but for some reason, &lt;code&gt;markAllAsDirty()&lt;/code&gt; was not available until v20.&lt;/p&gt;
&lt;h2&gt;Router&lt;/h2&gt;
&lt;h3&gt;Scroll options&lt;/h3&gt;
&lt;p&gt;It is now possible to pass options to
&lt;code&gt;ViewportScroller.scrollToAnchor()/scrollToPosition()&lt;/code&gt;.
All native scroll &lt;a href=&quot;&quot;&gt;options&lt;/a&gt; are supported,
for example &lt;code&gt;behavior&lt;/code&gt;:
&lt;code&gt;this.scroller.scrollToPosition([0, 10], { behavior: &amp;#39;smooth&amp;#39; })&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Resolvers&lt;/h3&gt;
&lt;p&gt;A good news for those using resolvers in the router:
they can now read the resolved data from the parent route:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;provideRouter&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;([&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    path&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;users/:id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    resolve&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; userResolver &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // ☝️ user resolver in the parent route&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    children&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;        path&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;posts&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;        resolve&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; posts&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; postsResolver &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;        // ☝️ route.data.user is now available in the posts resolver&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;        component&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; UserPosts&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;      // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;    ]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Asynchronous redirects&lt;/h3&gt;
&lt;p&gt;When defining a redirect in the route configuration,
the &lt;code&gt;redirectTo&lt;/code&gt; option accepts a function that can now be asynchronous
by returning a promise or an observable that resolves to a redirect.
This is technically a breaking change as the returned type evolved.&lt;/p&gt;
&lt;h3&gt;Custom elements support&lt;/h3&gt;
&lt;p&gt;Developers writing Web Components out there will be pleased
to know that it is now possible to use a custom element
as the host of a &lt;code&gt;RouterLink&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Http&lt;/h2&gt;
&lt;h3&gt;Resource API changes&lt;/h3&gt;
&lt;p&gt;The resource APIs continue to evolve with the feedback from the RFCs,
slowly shaping them into a more stable API that we will use to build future applications.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;resource()&lt;/code&gt; had its &lt;code&gt;query&lt;/code&gt; parameter renamed to &lt;code&gt;params&lt;/code&gt;
and &lt;code&gt;rxResource()&lt;/code&gt; had its &lt;code&gt;loader&lt;/code&gt; parameter renamed to &lt;code&gt;stream&lt;/code&gt;.
The &lt;code&gt;reload&lt;/code&gt; method has been moved from the base &lt;code&gt;Resource&lt;/code&gt; class
to the &lt;code&gt;WritableResource&lt;/code&gt; class which means only mutable resources can now be reloaded.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;httpResource&lt;/code&gt; also received some changes in v20
(you can check out &lt;a href=&quot;/2025/02/20/angular-http-resource/&quot;&gt;our previous article&lt;/a&gt;
to refresh your memory):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the &lt;code&gt;map&lt;/code&gt; option has been renamed &lt;code&gt;parse&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;the HTTP &lt;code&gt;context&lt;/code&gt; can now be specified in the options;&lt;/li&gt;
&lt;li&gt;the request must now always be reactive.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The last point means that you can no longer write
&lt;code&gt;httpResource&amp;lt;Array&amp;lt;UserModel&amp;gt;&amp;gt;(&amp;#39;/users&amp;#39;)&lt;/code&gt;
but now have to use &lt;code&gt;httpResource&amp;lt;Array&amp;lt;UserModel&amp;gt;&amp;gt;(() =&amp;gt; &amp;#39;/users&amp;#39;)&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;keepalive support&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;HttpClient&lt;/code&gt; now supports the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Request/keepalive&quot;&gt;keepalive&lt;/a&gt;
option when using the Fetch API (which is the case if you use the &lt;code&gt;withFetch()&lt;/code&gt; option).
When set to &lt;code&gt;true&lt;/code&gt;, the browser will not abort the associated request
if the page that initiated it is unloaded before the request is complete.&lt;/p&gt;
&lt;h2&gt;Profiling&lt;/h2&gt;
&lt;p&gt;A new &lt;code&gt;enableProfiling()&lt;/code&gt; function has been added to &lt;code&gt;@angular/core&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If called in your application, it will enable some profiling features in Angular that will help you to analyze the performance of your application.
Angular internally uses the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Performance/mark&quot;&gt;Performance API&lt;/a&gt; to tag the usage of some of the framework APIs (change detection, template, outputs, defer, etc.).
You can then use the Chrome Devtools to record a performance profile of your application and analyze the time spent in Angular, using the custom track added by Angular:&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;img class=&quot;img-fluid&quot; src=&quot;/assets/images/2025-05-29/angular-performance-devtools.png&quot; alt=&quot;Angular custom track in Chrome Devtools&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;This can be useful to identify why a specific page
or the startup of an application is slow.&lt;/p&gt;
&lt;h2&gt;Devtools&lt;/h2&gt;
&lt;p&gt;The Angular Devtools now mark &lt;code&gt;OnPush&lt;/code&gt; components as such in the component tree.
Deferred blocks are now also displayed.
The signal support is also improving
and we should soon be able to see the signals tree in the devtools.&lt;/p&gt;
&lt;h2&gt;SSR&lt;/h2&gt;
&lt;p&gt;On the SSR side,
the &lt;code&gt;withI18nSupport()&lt;/code&gt; and &lt;code&gt;withIncrementalHydration()&lt;/code&gt; APIs have been stabilized.&lt;/p&gt;
&lt;p&gt;The schematics now generate a server based on Express v5,
and the code is slightly different as you can see
in our &lt;a href=&quot;https://github.com/cexbrayat/angular-cli-ssr-diff/compare/19.0.0...20.0.0&quot;&gt;angular-cli-ssr-diff&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;provideServerRendering()&lt;/code&gt; and &lt;code&gt;provideServerRoutesConfig(serverRoutes)&lt;/code&gt;
are now combined into a single &lt;code&gt;provideServerRendering(withRoutes(serverRoutes))&lt;/code&gt; function.
&lt;code&gt;provideServerRendering&lt;/code&gt; is now in &lt;code&gt;@angular/ssr&lt;/code&gt; instead of &lt;code&gt;@angular/platform-server&lt;/code&gt;.
A migration will take care of this refactoring for you if you run &lt;code&gt;ng update&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When generating a new application with the CLI the &lt;code&gt;--server-routing&lt;/code&gt; option
has been removed and the &lt;code&gt;--ssr&lt;/code&gt; option now generates a server with routing support by default.&lt;/p&gt;
&lt;h2&gt;Angular CLI&lt;/h2&gt;
&lt;p&gt;As you can see in &lt;a href=&quot;https://github.com/cexbrayat/angular-cli-diff/compare/19.2.0...20.0.0&quot;&gt;angular-cli-diff&lt;/a&gt;,
the project generated by the CLI has changed a lot.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s dive into the changes.&lt;/p&gt;
&lt;h3&gt;Updated naming for 2025 style guide&lt;/h3&gt;
&lt;p&gt;As mentioned above, the Angular style guide has changed a lot.
The CLI has been updated to use the new naming convention by default.
The generated files when running &lt;code&gt;ng g c user&lt;/code&gt; are now named &lt;code&gt;user.ts&lt;/code&gt; instead of &lt;code&gt;user.component.ts&lt;/code&gt;,
&lt;code&gt;user.html&lt;/code&gt; instead of &lt;code&gt;user.component.html&lt;/code&gt;,
and &lt;code&gt;user.css&lt;/code&gt; instead of &lt;code&gt;user.component.css&lt;/code&gt;, etc.
The name of a component is now &lt;code&gt;User&lt;/code&gt; instead of &lt;code&gt;UserComponent&lt;/code&gt;.
You can opt out of this behavior by using the &lt;code&gt;--type=component&lt;/code&gt; option
when generating a component,
or by setting the &lt;code&gt;type&lt;/code&gt; option to &lt;code&gt;component&lt;/code&gt; in the CLI configuration file.&lt;/p&gt;
&lt;p&gt;If you want to, you can generate a component template with the &lt;code&gt;.ng.html&lt;/code&gt; extension
by using &lt;code&gt;ng g c user --ng-html&lt;/code&gt; or by setting the &lt;code&gt;ngHtml&lt;/code&gt; option to &lt;code&gt;true&lt;/code&gt; in the CLI configuration file (the option is disabled by default).&lt;/p&gt;
&lt;p&gt;The same goes for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;directives: &lt;code&gt;ng g d highlight&lt;/code&gt; will generate a &lt;code&gt;highlight.ts&lt;/code&gt;
file instead of &lt;code&gt;highlight.directive.ts&lt;/code&gt;,
and the class will be named &lt;code&gt;Highlight&lt;/code&gt; instead of &lt;code&gt;HighlightDirective&lt;/code&gt;,
except if you use the &lt;code&gt;--type=directive&lt;/code&gt; option.&lt;/li&gt;
&lt;li&gt;same thing for services: &lt;code&gt;ng g s user&lt;/code&gt; will generate a &lt;code&gt;user.ts&lt;/code&gt;
file instead of &lt;code&gt;user.service.ts&lt;/code&gt;,
and the class will be named &lt;code&gt;User&lt;/code&gt; instead of &lt;code&gt;UserService&lt;/code&gt;,
except if you use the &lt;code&gt;--type=service&lt;/code&gt; option.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For pipes, resolver, interceptors guards, and modules:
the names are the same as previously but the separator in the file name becomes
a dash instead of a dot by default.&lt;/p&gt;
&lt;p&gt;For example, &lt;code&gt;ng g p from-now&lt;/code&gt; will generate a &lt;code&gt;from-now-pipe.ts&lt;/code&gt;
file instead of &lt;code&gt;from-now.pipe.ts&lt;/code&gt;, except if you use the &lt;code&gt;--type-separator=.&lt;/code&gt; option
The class will still be named &lt;code&gt;FromNowPipe&lt;/code&gt; though.&lt;/p&gt;
&lt;p&gt;To keep the same behavior as before,
an automatic migration has been added to the CLI
to configure &lt;code&gt;angular.json&lt;/code&gt; to use the old naming convention:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;schematics&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;@schematics/angular:component&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;component&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;@schematics/angular:directive&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;directive&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;@schematics/angular:service&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;service&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;@schematics/angular:guard&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;typeSeparator&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;@schematics/angular:interceptor&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;typeSeparator&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;@schematics/angular:module&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;typeSeparator&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;@schematics/angular:pipe&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;typeSeparator&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;@schematics/angular:resolver&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;typeSeparator&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;TypeScript configuration&lt;/h3&gt;
&lt;p&gt;There are two big changes in the TypeScript configuration.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;module&lt;/code&gt; option is now set to &lt;code&gt;preserve&lt;/code&gt; instead of &lt;code&gt;es2022&lt;/code&gt;
to reflect more accurately how modern bundlers work.
This removes the need to set the &lt;code&gt;esModuleInterop&lt;/code&gt; and &lt;code&gt;moduleResolution&lt;/code&gt; options.&lt;/p&gt;
&lt;p&gt;The other change is more notable:
the generated &lt;code&gt;tsconfig.json&lt;/code&gt; file now uses a &amp;quot;solution&amp;quot; style
configuration with references
to &lt;code&gt;tsconfig.app.json&lt;/code&gt; and &lt;code&gt;tsconfig.spec.json&lt;/code&gt;
(instead of having the &lt;code&gt;tsconfig.app.json&lt;/code&gt; and &lt;code&gt;tsconfig.spec.json&lt;/code&gt; files
extend the base &lt;code&gt;tsconfig.json&lt;/code&gt;).
This should greatly help tools and IDEs understand the project structure!&lt;/p&gt;
&lt;h3&gt;Simplified angular.json&lt;/h3&gt;
&lt;p&gt;A new project now directly uses the &lt;code&gt;@angular/build&lt;/code&gt; package
instead of &lt;code&gt;@angular-devkit/build-angular&lt;/code&gt;.
This removes the need to install this package and all the
Webpack-related transitive dependencies
and results in a big reduction in the &lt;code&gt;node_modules&lt;/code&gt; installed (nearly 200Mb!).&lt;/p&gt;
&lt;p&gt;If you&amp;#39;re updating a CLI project, a migration will update
your &lt;code&gt;angular.json&lt;/code&gt; file to use the new builder
if you aren&amp;#39;t already using it.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;angular.json&lt;/code&gt; file has also been simplified a bit,
with some options like &lt;code&gt;outputPath&lt;/code&gt;, &lt;code&gt;index&lt;/code&gt;, and &lt;code&gt;scripts&lt;/code&gt; removed
as they now have a sensible default value.&lt;/p&gt;
&lt;h3&gt;Browserslist configuration&lt;/h3&gt;
&lt;p&gt;The CLI has been using &lt;code&gt;browserslist&lt;/code&gt; for a while now,
and you can tweak the supported browsers by generating the &lt;code&gt;browserslist&lt;/code&gt; file
using &lt;code&gt;ng generate config browserslist&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The generated configuration used to target the last 2 versions of each browser,
which is a moving target and depends on the time of the build.&lt;/p&gt;
&lt;p&gt;The Angular team changed its support policy
and now targets the &amp;quot;widely available&amp;quot; baseline.
It includes browsers released less than 30 months
of the chosen date within Baseline&amp;#39;s core browser set (Chrome, Edge, Firefox, Safari) and
targets supporting approximately 95% of web users (see &lt;a href=&quot;https://web.dev/baseline&quot;&gt;https://web.dev/baseline&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The CLI now generates a &lt;code&gt;browserslist&lt;/code&gt; file with the following content
for v20, targeting browsers released in the last 30 months:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Chrome &gt;= 107&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ChromeAndroid &gt;= 107&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Edge &gt;= 107&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Firefox &gt;= 104&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;FirefoxAndroid &gt;= 104&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Safari &gt;= 16&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;iOS &gt;= 16&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you use a custom &lt;code&gt;browserslist&lt;/code&gt; configuration with a different set of browsers,
you will see a warning like this:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;One or more browsers which are configured in the project&apos;s Browserslist configuration fall outside Angular&apos;s browser support for this version.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Unsupported browsers:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;chrome 106, chrome 105&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sass package importers&lt;/h3&gt;
&lt;p&gt;Sass supports &lt;code&gt;pkg:&lt;/code&gt; importers to import packages from package managers
(see &lt;a href=&quot;https://sass-lang.com/blog/announcing-pkg-importers/&quot;&gt;Sass blog post&lt;/a&gt;).
The CLI now supports this feature as well when using Sass as a preprocessor,
so you can write &lt;code&gt;@use &amp;#39;pkg:@angular/material&amp;#39; as mat;&lt;/code&gt; in your Sass files for example.&lt;/p&gt;
&lt;h3&gt;Ahead of Time testing and code coverage for templates&lt;/h3&gt;
&lt;p&gt;If you&amp;#39;ve been using Angular for a while, you may remember a time when
we had both Ahead-of-Time (AoT) and Just-in-Time (JiT) compilation for our applications.
Ivy came around with a faster compiler, allowing us to always use AoT compilation.
The CLI introduced the support of AoT testing with the &lt;code&gt;ng test&lt;/code&gt; command in v19.2,
but it was not really usable at that time,
mostly because the &lt;code&gt;TestBed&lt;/code&gt; allows to overwrite component metadata
and this was not compatible with AoT compilation.&lt;/p&gt;
&lt;p&gt;This has been fixed, and you can now use AoT compilation for your tests!
This is a great improvement for consistency,
as it allows you to run your tests in the same mode as your production code.&lt;/p&gt;
&lt;p&gt;To do so, you can add the &lt;code&gt;&amp;quot;aot&amp;quot;: true&lt;/code&gt; option to your &lt;code&gt;angular.json&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;builder&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;@angular/build:karma&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;aot&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; true,&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that you may have to fix issues in your tests when switching to AoT compilation,
as you may have forgotten some required inputs in your tests for example.
There are still a few issues left with &lt;code&gt;overrideComponent&lt;/code&gt; that you may run into as well.&lt;/p&gt;
&lt;p&gt;Running tests with AoT compilation also provides code coverage for the templates,
which is a nice addition and may help to catch some untested parts of your components.&lt;/p&gt;
&lt;p&gt;It looks like the test times are roughly the same with AoT compilation.&lt;/p&gt;
&lt;h3&gt;Testing with Vitest 🚀&lt;/h3&gt;
&lt;p&gt;The CLI now supports running tests with &lt;a href=&quot;https://vitest.dev/&quot;&gt;Vitest&lt;/a&gt;,
a fast and modern test framework that is based on Vite.&lt;/p&gt;
&lt;p&gt;The Angular team is still looking for a good replacement for Karma
and Vitest was at first discarded as an option
when the team focused on Jest (v16) and Web Test Runner (in v17).
These Jest and WTR integrations are still experimental,
and have not been updated in a while.&lt;/p&gt;
&lt;p&gt;In the meantime, Vitest has exploded in popularity in other ecosystems,
and the Angular team decided to give it a try.&lt;/p&gt;
&lt;p&gt;A new builder has been added to the CLI, named &lt;code&gt;unit-test&lt;/code&gt;.
You can use it by replacing the &lt;code&gt;@angular/build:karma&lt;/code&gt; or &lt;code&gt;@angular-devkit/build-angular:karma&lt;/code&gt; builders
with &lt;code&gt;@angular/build:unit-test&lt;/code&gt; in your &lt;code&gt;angular.json&lt;/code&gt; file.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;builder&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;@angular/build:unit-test&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;tsConfig&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;tsconfig.spec.json&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;buildTarget&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;::development&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;runner&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;vitest&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this configuration, you can remove all the karma and jasmine dependencies from your project and will need to install the &lt;code&gt;vitest&lt;/code&gt; package instead.&lt;/p&gt;
&lt;p&gt;Note the &lt;code&gt;runner&lt;/code&gt; option which specifies &lt;code&gt;&amp;quot;vitest&amp;quot;&lt;/code&gt; (but can also accept &lt;code&gt;&amp;quot;karma&amp;quot;&lt;/code&gt;).
With this builder, you no longer need to configure how the tests should run with polyfills, assets, etc.
You must now use a &lt;code&gt;&amp;quot;buildTarget&amp;quot;&lt;/code&gt; with one of your build configurations as a value.
Note that in my example above, I used the &lt;code&gt;development&lt;/code&gt; build configuration,
which means that the tests will run with AoT compilation.&lt;/p&gt;
&lt;p&gt;By default, Vitest runs in a Node environment,
and uses &lt;a href=&quot;https://github.com/jsdom/jsdom&quot;&gt;jsdom&lt;/a&gt;
to simulate a browser environment,
which you&amp;#39;ll need to install as a dev dependency.&lt;/p&gt;
&lt;p&gt;If you are migrating a project from Karma/Jasmine to Vitest,
you&amp;#39;ll need to update your tests to use Vitest APIs instead of Jasmine ones.
You shouldn&amp;#39;t have to add imports for the Vitest APIs though,
as the CLI configures them to be global.
To make sure your IDE picks them up,
replace the &lt;code&gt;jasmine&lt;/code&gt; types in your &lt;code&gt;tsconfig.spec.json&lt;/code&gt; file with &lt;code&gt;vitest/globals&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;types&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;vitest/globals&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also run your tests in a real browser environment.
Vitest has a &lt;code&gt;browser&lt;/code&gt; mode, which is still experimental
but works well enough.
You&amp;#39;ll need to install the &lt;code&gt;@vitest/browser&lt;/code&gt; package
and can remove the JSDOM dependency from your project.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;runner&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;vitest&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;browsers&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;chromium&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// can be &quot;firefox&quot;, &quot;webkit&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The browser will be downloaded automatically when you run your tests,
using either &lt;a href=&quot;https://playwright.dev/&quot;&gt;playwright&lt;/a&gt; or &lt;a href=&quot;https://webdriver.io/&quot;&gt;WebdriverIO&lt;/a&gt;,
as the CLI indicates in the error message below when you run &lt;code&gt;ng test&lt;/code&gt; without having one of these packages installed:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;The &quot;browsers&quot; option requires either &quot;playwright&quot; or &quot;webdriverio&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;to be installed within the project.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Please install one of these packages and rerun the test command.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once Playwright or WebdriverIO is installed,
you can run your tests in a real browser environment:
the CLI will download the browsers automatically
and run the tests in it 🚀.&lt;/p&gt;
&lt;p&gt;The execution times are a bit slower than with Karma though for a complete run.
But the watch mode is faster, as it only runs the tests that are affected by the changes,
whereas Karma runs all the tests every time.&lt;/p&gt;
&lt;p&gt;The watch mode is by default as with the current Karma builder,
but it is automatically disabled on CI or if there is no interactive terminal,
which is closer to what vitest does by default.
This means you no longer have to add the &lt;code&gt;--no-watch&lt;/code&gt; option
to the &lt;code&gt;ng test&lt;/code&gt; command to run the tests in CI.&lt;/p&gt;
&lt;p&gt;Speaking of flags, there is a new one with this builder called &lt;code&gt;--debug&lt;/code&gt;.
The debug mode only works with vitest as a runner,
and with jsdom or in browser mode using Playwright.
It hooks the Node Inspector into the test runner to allow you to debug your tests
by connecting to it with a debugger.&lt;/p&gt;
&lt;p&gt;There are a few limitations with this new test runner as it is still experimental.
For example, you can&amp;#39;t define a &amp;quot;setup&amp;quot; file to set up your tests as you can with Karma
which is usually very handy to add custom matchers or do some assertions after each test.
But the &lt;code&gt;unit-test&lt;/code&gt; builder allows you to define a &lt;code&gt;providersFile&lt;/code&gt; option,
which is a file that will be loaded before the tests are run,
with whatever providers you want to add to the test bed.
This is useful for setting up zoneless testing,
as you can add &lt;code&gt;provideZonelessChangeDetection()&lt;/code&gt; in this file:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; provideZonelessChangeDetection&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;@angular/core/testing&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;provideZonelessChangeDetection&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can&amp;#39;t specify a Karma config file or Vitest config file for now,
which means that you can&amp;#39;t run the tests in headless mode for example,
or configure a custom reporter.&lt;/p&gt;
&lt;p&gt;You can configure a reporter or code coverage exclusions directly in the &lt;code&gt;angular.json&lt;/code&gt; file though:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;builder&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;@angular/build:unit-test&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;tsConfig&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;tsconfig.spec.json&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;buildTarget&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;::development&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;runner&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;vitest&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;reporter&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;],&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // uses @vitest/ui&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;codeCoverage&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; true,&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // uses @vitest/coverage-v8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;codeCoverageExclude&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;src/app/ignore.ts&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Automatic Chrome workspace folders&lt;/h3&gt;
&lt;p&gt;The vite server now automatically serves a &lt;code&gt;com.chrome.devtools.json&lt;/code&gt; file
that the Chrome Devtools automatically picks up
(behind a flag for now, but it will be enabled by default in the future).
This file contains the project location on your disk
and allows to directly edit source files from the Devtools,
with the changes being saved in the original files.&lt;/p&gt;
&lt;p&gt;You can enable this feature in Chrome by following the &lt;a href=&quot;https://chromium.googlesource.com/devtools/devtools-frontend/+/main/docs/ecosystem/automatic_workspace_folders.md&quot;&gt;docs here&lt;/a&gt;.
When done, you&amp;#39;ll see a new &amp;quot;Workspace&amp;quot; tab in the Source panel of the Devtools.
You&amp;#39;ll be asked to connect to the workspace,
and then you&amp;#39;ll see a file tree with all the files in your project.
You can then open any file in the Devtools and edit it.
When saving the file, it will be saved in the original file on your disk
and the changes will be reflected in the application.&lt;/p&gt;
&lt;h3&gt;Sourcemaps without sources&lt;/h3&gt;
&lt;p&gt;The CLI can now generate sourcemaps without the &lt;code&gt;sourcesContent&lt;/code&gt; field
which contains the original source code.
To do so, you can set the &lt;code&gt;sourceMap&lt;/code&gt; option to:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;sourceMap&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;scripts&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; true,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;styles&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; true,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;sourcesContent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can be useful if you want to deploy sourcemaps to production
to have better error reporting that includes the original source names,
but you don&amp;#39;t want to expose the original source code to the users.&lt;/p&gt;
&lt;h2&gt;Angular joins the AI train&lt;/h2&gt;
&lt;p&gt;As AI is everywhere nowadays, Angular could not avoid joining the hype train.
The Angular docs are now exposed in a text file for LLMs
at the root of the repository following the &lt;code&gt;llms-full.txt&lt;/code&gt; emerging convention.
If added to your AI favorite tool&amp;#39;s context,
it should help generate better Angular code.&lt;/p&gt;
&lt;h2&gt;What to expect in Angular v21&lt;/h2&gt;
&lt;p&gt;The Angular team will probably communicate about these features soon,
but I can&amp;#39;t resist sharing two projects that they have been cooking behind the scenes!&lt;/p&gt;
&lt;h3&gt;Selectorless components 😲&lt;/h3&gt;
&lt;p&gt;The beginning of a new experiment started: selectorless components.
In the future, we may be able to use components and directives
without a selector in our templates
and without having to add the &lt;code&gt;imports&lt;/code&gt; array in our component metadata!&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; User&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;./user/user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// ☝️ TS import is still necessary&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [name]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;name()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; (selected)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;selectUser()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // but no Angular imports are needed! 😲&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; App&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Components can be used in templates without a selector
by using their class name directly.
Same thing for directives, but they currently require an &lt;code&gt;@&lt;/code&gt; prefix:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; @CdkDrag(cdkDragLockAxis&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [name]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;name()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; (selected)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;selectUser()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pipes can also be used without a name:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; FromNowPipe&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;./from-now-pipe&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; date &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; FromNowPipe&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; App&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Super big warning: the syntax is far from being decided.
Only the compiler part has been done in v20,
so nothing of the above is testable for now
but we can already see that it opens a lot of possibilities.
A RFC should probably come soon.&lt;/p&gt;
&lt;h3&gt;Signal Forms&lt;/h3&gt;
&lt;p&gt;In parallel, some prototyping has been done for signal forms.
Is it based on template forms or reactive forms?
Nope, it looks like it is going to be a brand new third way to write forms in Angular.
Let&amp;#39;s say we have a &lt;code&gt;userModel&lt;/code&gt; signal data we want to edit.
Angular will provide a &lt;code&gt;form()&lt;/code&gt; function to get a &lt;code&gt;Field&lt;/code&gt;,
a new class that owns the state of the form (valid, touched, etc).&lt;/p&gt;
&lt;p&gt;This code below is only available in the prototyping branch,
so don&amp;#39;t expect to use it in v20 😉:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  selector&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;user-form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  imports&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [FieldDirective]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // ☝️ new directive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; `&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Username: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [field]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;userForm.username&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;      &amp;#x3C;!-- ☝️ used to bind fields --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Name: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [field]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;userForm.name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Age: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [field]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;userForm.age&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;  `&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; UserFormComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  userModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; signal&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;UserModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; username&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; age&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  protected&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; readonly&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; userForm&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; Field&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; form&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // ☝️ form() is a new function and returns a Field&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;    userModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // data to edit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;userPath&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; FieldPath&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      disabled(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;userPath&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;username&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Username cannot be changed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      required(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;userPath&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      error(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;userPath&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;age&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ({&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; })&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; value() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 18&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Must be 18 or older&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // ☝️ schema that allows to define the dynamic behavior of fields (enabled/disabled)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // and the validation, with provided and custom validators&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  )&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you want to learn more, you can check out the
&lt;a href=&quot;https://github.com/angular/angular/blob/37c5ff61c69cc0460e9540800ba2cecceacf9e11/packages/forms/experimental/docs/signal-forms.md&quot;&gt;current design doc&lt;/a&gt;
which is really interesting or wait for the probably not very far RFC that will discuss all this.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;That were a lot of new features in Angular v20!&lt;/p&gt;
&lt;p&gt;v21 will hopefully bring us the first usable version of signal forms
and/or this new selectorless syntax.
Stay tuned!&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>What&apos;s new in Angular 19.2?</title>
    <link href="https://blog.ninja-squad.com/2025/02/26/what-is-new-angular-19.2"/>
    <updated>2025-02-26T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2025/02/26/what-is-new-angular-19.2</id>
    <content type="html">
      &lt;p&gt;Angular&amp;nbsp;19.2.0 is here!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;a href=&quot;https://github.com/angular/angular/releases/tag/19.2.0&quot;&gt;
    &lt;img class=&quot;img-fluid&quot; style=&quot;max-width: 60%&quot; src=&quot;/assets/images/angular_gradient.webp&quot; alt=&quot;Angular logo&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;This is a minor release with some nice features: let&amp;#39;s dive in!&lt;/p&gt;
&lt;h2&gt;Angular the documentary&lt;/h2&gt;
&lt;p&gt;This is not really linked to Angular v19.2, but it&amp;#39;s worth mentioning
that the Honeypot channel released a documentary retracing the history of Angular,
with interviews of the Angular team members (old and new):&lt;/p&gt;
&lt;p&gt;👉 &lt;a href=&quot;https://youtu.be/cRC9DlH45lA?si=pStu61Y3hPOGzh8X&quot;&gt;Documentary on youtube&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;TypeScript 5.8 support&lt;/h2&gt;
&lt;p&gt;Angular v19.2 now supports TypeScript 5.8, which is still in RC but should be out soon.
This means you&amp;#39;ll be able to use the latest version of TypeScript in your Angular applications.
You can check out the &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-8-rc/&quot;&gt;TypeScript 5.8 release notes&lt;/a&gt;
to learn more about the new features.&lt;/p&gt;
&lt;h2&gt;resource() and rxResource() changes&lt;/h2&gt;
&lt;p&gt;Some changes happened in the recently introduced &lt;code&gt;resource&lt;/code&gt; and &lt;code&gt;rxResource&lt;/code&gt; APIs.
&lt;code&gt;resource&lt;/code&gt; was introduced in &lt;a href=&quot;/2024/11/19/what-is-new-angular-19.0/&quot;&gt;Angular 19.0&lt;/a&gt;
as an experimental API to handle asynchronous resources in Angular applications:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;list&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(): ResourceRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;UserModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; undefined&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  return &lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;resource&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    loader&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;      const response &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; fetch&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;/users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      return&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; response.json(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) as &lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;UserModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  })&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Angular v19.2 adds the possibility to define a &lt;code&gt;defaultValue&lt;/code&gt; option that will be used as the initial value of the resource
or when the resource is in error (instead of &lt;code&gt;undefined&lt;/code&gt; by default):&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;list&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(): ResourceRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;UserModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; return &lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;resource&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // 👇 used when idle, loading, or in error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    defaultValue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; [],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    loader&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;      const response &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; fetch&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;/users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      return&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; response.json(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) as &lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;UserModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; })&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Angular v19.2 also added the possibility to create resources with streamed response data.
A streaming resource is defined with a stream option instead of a loader option.
This stream function returns a promise of a signal (yes, I needed to read it twice as well).
The signal value must be of type &lt;code&gt;ResourceStreamItem&lt;/code&gt;:
an object with a value or an error property.
When the promise is resolved, the loader can continue to update that signal over time,
and the resource will update its value and error every time the signal’s item changes.&lt;/p&gt;
&lt;p&gt;You can build this stream yourself, using a WebSocket for example.
We can also imagine that some libraries such as Firebase
could provide a stream function that would be directly usable:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;list&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(): ResourceRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;UserModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; undefined&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; return &lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;resource&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // firebaseCollection does not exist in real-life&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    stream&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; abortSignal &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; firebaseCollection&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; abortSignal)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; })&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This stream feature had been leveraged by the &lt;code&gt;rxResource&lt;/code&gt; API,
and you can now have a stream of values by returning an observable that emits several times.
The resource will be updated every time a new value is emitted,
whereas only the first value was emitted when introduced in Angular v19.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;readonly sortOrder &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; signal&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;asc&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;desc&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;asc&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;readonly usersResource &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; rxResource&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  request&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; sort&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;sortOrder&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇 stream that fetches the value now and every 10s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  loader&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ({&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; request&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; })&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    timer&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 10000&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;pipe&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;      switchMap&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;httpClient&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;UserModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;/users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; params&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; sort&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; request&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;sort &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;New httpResource() API!&lt;/h2&gt;
&lt;p&gt;The main feature of this release is the introduction of the &lt;code&gt;httpResource&lt;/code&gt; API.
This API allows you to easily create resources that fetch data from an HTTP endpoint.&lt;/p&gt;
&lt;p&gt;We wrote a dedicated blog post to explain how to use it:&lt;/p&gt;
&lt;p&gt;👉 &lt;a href=&quot;/2025/02/20/angular-http-resource/&quot;&gt;A guide to HTTP calls with &lt;code&gt;httpResource()&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The official RFCs for &lt;a href=&quot;https://github.com/angular/angular/discussions/60120&quot;&gt;Resource Architecture&lt;/a&gt;
and &lt;a href=&quot;https://github.com/angular/angular/discussions/60121&quot;&gt;Resource APIS&lt;/a&gt;
are also out if you&amp;#39;re curious.&lt;/p&gt;
&lt;h2&gt;Template strings in templates&lt;/h2&gt;
&lt;p&gt;The Angular compiler now supports template strings in templates:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; `&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Hello, &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [class]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;`btn-${theme()}`&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Toggle&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;theme&lt;/code&gt; are signals that contain strings.
You can even use pipes in the dynamic part of the template string:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; `&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Hello, &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; uppercase&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a nice addition and I hope we&amp;#39;ll see arrow functions in templates soon!&lt;/p&gt;
&lt;h2&gt;Migration to self-closing tags&lt;/h2&gt;
&lt;p&gt;A migration has been added to convert void elements to self-closing tags.
This is just a cosmetic change, and some of you may have already done it via &lt;code&gt;angular-eslint&lt;/code&gt;
and its &lt;code&gt;prefer-self-closing-tags&lt;/code&gt; rule.&lt;/p&gt;
&lt;p&gt;If that&amp;#39;s not the case for you, you can run:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ng&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; generate&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; @angular/core:self-closing-tag&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Forms validators&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;Validators.required&lt;/code&gt;, &lt;code&gt;Validators.minLength&lt;/code&gt;, and &lt;code&gt;Validators.maxLength&lt;/code&gt; validators
now work with &lt;code&gt;Set&lt;/code&gt; in addition to &lt;code&gt;Array&lt;/code&gt; and &lt;code&gt;string&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; atLeastTwoElementsValidator &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Validators&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;minLength&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// minLength error before v19.2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;atLeastTwoElementsValidator&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; FormControl&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // string&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;atLeastTwoElementsValidator&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; FormControl&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;]))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // Array&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// 👇 NEW in v19.2! minLength error as well with a Set&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;atLeastTwoElementsValidator&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; FormControl&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; Set&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;])))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // Set&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Animation package&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;@angular/animations&lt;/code&gt; package is slowly being retired:
there has been no major update since its author left the Angular team a few years ago,
and it is not actively maintained anymore.
The team has removed dependencies on it in most packages (and in Angular Material as well),
which means that you now safely remove it from your project if you don&amp;#39;t use it directly.
To reflect that, the project skeleton generated by the CLI does not include it anymore in v19.2.&lt;/p&gt;
&lt;h2&gt;Angular CLI&lt;/h2&gt;
&lt;h3&gt;AoT support for Karma, Jest, and WTR&lt;/h3&gt;
&lt;p&gt;It is now possible to run your tests with AOT compilation with Karma, Jest, and Web Test Runner, instead of the default JIT compilation that has been used so far.
This is great as it can catch issues in your test components (missing required inputs, etc).&lt;/p&gt;
&lt;p&gt;Sadly, some test features are not available with AOT compilation in tests.
For example, &lt;code&gt;TestBed.overrideComponent&lt;/code&gt;, &lt;code&gt;TestBed.overrideTemplate&lt;/code&gt;, etc are not supported
as they rely on JIT compilation.
I really hope that we&amp;#39;ll soon have new &lt;code&gt;TestBed&lt;/code&gt; APIs that work with AOT compilation!&lt;/p&gt;
&lt;p&gt;In the meantime, you can give it a try by adding the &lt;code&gt;aot: true&lt;/code&gt;
option in your &lt;code&gt;angular.json&lt;/code&gt; configuration file.&lt;/p&gt;
&lt;h3&gt;Karma builder&lt;/h3&gt;
&lt;p&gt;The Karma application builder (introduced in &lt;a href=&quot;/2024/11/19/what-is-new-angular-19.0/&quot;&gt;v19&lt;/a&gt;)
has been moved to the &lt;code&gt;@angular/build&lt;/code&gt; package.
This means you can now only use this dependency
and get rid of the &lt;code&gt;@angular-devkit/build-angular&lt;/code&gt; one.&lt;/p&gt;
&lt;h3&gt;SSR&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;provideServerRoutesConfig&lt;/code&gt; has been deprecated and renamed &lt;code&gt;provideServerRouting&lt;/code&gt;,
and its &lt;code&gt;appShellRoute&lt;/code&gt; option has been replaced with a &lt;code&gt;withAppShell&lt;/code&gt; option,
to make the API similar to the other in Angular.&lt;/p&gt;
&lt;p&gt;Before:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;provideServerRoutesConfig&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(serverRoutes&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; appShellRoute&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;provideServerRouting&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(serverRoutes&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; withAppShell&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(AppComponent))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A note-worthy new feature: routes defined with a &lt;code&gt;matcher&lt;/code&gt; are now supported by Angular SSR,
allowing us to define their render mode.
Note that it can only be &lt;code&gt;Server&lt;/code&gt; or &lt;code&gt;Client&lt;/code&gt; for these routes but not &lt;code&gt;Prerender&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;That&amp;#39;s all for this release.
The next one should be v20, and we hope to see some news on the &amp;quot;forms with signals&amp;quot; 🤞
Stay tuned!&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>A guide to HTTP calls in Angular using httpResource()</title>
    <link href="https://blog.ninja-squad.com/2025/02/20/angular-http-resource"/>
    <updated>2025-02-20T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2025/02/20/angular-http-resource</id>
    <content type="html">
      &lt;p&gt;Angular v19.2 introduced a dedicated (and experimental) function
to create resources that use HTTP requests: &lt;code&gt;httpResource()&lt;/code&gt; in the &lt;code&gt;@angular/common/http package&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This function uses &lt;code&gt;HttpClient&lt;/code&gt; under the hood,
allowing us to use our usual interceptors, testing utilities, etc.&lt;/p&gt;
&lt;p&gt;The most basic usage is to call this function with a function that returns the URL from which you want to fetch data:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;readonly usersResource &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; httpResource&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;UserModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;/users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;httpResource()&lt;/code&gt; returns an &lt;code&gt;HttpResourceRef&lt;/code&gt; with the same properties as &lt;code&gt;ResourceRef&lt;/code&gt;,
the type returned by &lt;code&gt;resource()&lt;/code&gt;, as it is built on top of it
(check out our &lt;a href=&quot;/2024/11/19/what-is-new-angular-19.0/&quot;&gt;blog post about Angular v19.0&lt;/a&gt; to learn more about &lt;code&gt;resource()&lt;/code&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;value&lt;/code&gt; is a signal that contains the deserialized JSON response body;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;status&lt;/code&gt; is a signal that contains the resource status (idle, loading, error, resolved, etc.);&lt;/li&gt;
&lt;li&gt;&lt;code&gt;error&lt;/code&gt; is a signal that contains the error if the request fails;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isLoading&lt;/code&gt; is a signal that indicates if the resource is loading;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reload()&lt;/code&gt; is a method that allows you to reload the resource;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;update()&lt;/code&gt; and &lt;code&gt;set()&lt;/code&gt; are methods that allow you to change the value of the resource;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;asReadonly()&lt;/code&gt; is a method that allows you to get a read-only version of the resource;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hasValue()&lt;/code&gt; is a method that allows you to know if the resource has a value;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;destroy()&lt;/code&gt; is a method that allows you to stop the resource.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It also contains a few more properties specific to HTTP resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;statusCode&lt;/code&gt; is a signal that contains the status code of the response as a &lt;code&gt;number&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;headers&lt;/code&gt; is a signal that contains the headers of the response as &lt;code&gt;HttpHeaders&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;progress&lt;/code&gt; is a signal that contains the download progress of the response as a &lt;code&gt;HttpProgressEvent&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is also possible to define a reactive resource 
by using a signal in the function that defines the URL.
The resource will automatically reload when the signal changes:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;readonly sortOrder &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; signal&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;asc&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;desc&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;asc&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;readonly sortedUsersResource &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; httpResource&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;UserModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; `&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;/users?sort=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;sortOrder&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you want to skip the reload,
you can return &lt;code&gt;undefined&lt;/code&gt; from the request function (as for &lt;code&gt;resource()&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;If you need more fine-grained control over the request,
you can also pass an &lt;code&gt;HttpResourceRequest&lt;/code&gt; object to the &lt;code&gt;httpResource(&lt;/code&gt;) function,
or a function that returns an &lt;code&gt;HttpResourceRequest&lt;/code&gt; object 
in case you want to make the request reactive.&lt;/p&gt;
&lt;p&gt;This object must have a &lt;code&gt;url&lt;/code&gt; property
and can have other options like &lt;code&gt;method&lt;/code&gt; (&lt;code&gt;GET&lt;/code&gt; by default), &lt;code&gt;params&lt;/code&gt;, &lt;code&gt;headers&lt;/code&gt;, &lt;code&gt;reportProgress&lt;/code&gt;, etc.
If you want to make the request reactive,
you can use signals in the &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;params&lt;/code&gt; or &lt;code&gt;headers&lt;/code&gt; properties.&lt;/p&gt;
&lt;p&gt;The above example would then look like:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;readonly sortedUsersResource &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; httpResource&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;UserModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  url&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; `&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;/users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  params&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; sort&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;sortOrder&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  headers&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; HttpHeaders&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;X-Custom-Header&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;customHeader&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can of course send a body with the request,
for example for a POST/PUT request,
using the &lt;code&gt;body&lt;/code&gt; property of the request object.
Note that, as we create the resource in a method,
we have to pass the &lt;code&gt;injector&lt;/code&gt; in the options as a second argument:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;injector &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; inject&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(Injector)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;filterUserResource&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; HttpResourceRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;UserModel &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; undefined&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; undefined;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;filterUser&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;filterUserResource&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; httpResource&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;UserModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      url&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; `&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;/users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      method&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;POST&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      body&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;        name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;JB&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      injector&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;injector&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  )&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that we will probably keep using the &lt;code&gt;HttpClient&lt;/code&gt; for mutations.&lt;/p&gt;
&lt;p&gt;In these options, you can also define:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;defaultValue&lt;/code&gt;, a default value of the resource, to use when idle, loading, or in error;&lt;/li&gt;
&lt;li&gt;an &lt;code&gt;equal&lt;/code&gt; function that defines the equality of two values;&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;map&lt;/code&gt; function that allows you to transform the response before setting it in the resource.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is also possible to request something else than JSON,
by using the &lt;code&gt;httpResource.text()&lt;/code&gt;, &lt;code&gt;httpResource.blob()&lt;/code&gt; or &lt;code&gt;httpResource.arrayBuffer()&lt;/code&gt; functions.&lt;/p&gt;
&lt;p&gt;Some of you may get a feeling of déjà vu with all this,
as it’s quite similar to the &lt;a href=&quot;https://tanstack.com/query/latest&quot;&gt;TanStack Query library&lt;/a&gt;,
I must insist that this is experimental and will probably evolve in the future.
Let’s see what the RFC process will bring us!&lt;/p&gt;
&lt;p&gt;Update: the RFCs are out for 
&lt;a href=&quot;https://github.com/angular/angular/discussions/60120&quot;&gt;Resource Architecture&lt;/a&gt;
and &lt;a href=&quot;https://github.com/angular/angular/discussions/60121&quot;&gt;Resource APIS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>What&apos;s new in Angular 19.1?</title>
    <link href="https://blog.ninja-squad.com/2025/01/15/what-is-new-angular-19.1"/>
    <updated>2025-01-15T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2025/01/15/what-is-new-angular-19.1</id>
    <content type="html">
      &lt;p&gt;Angular&amp;nbsp;19.1.0 is here!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;a href=&quot;https://github.com/angular/angular/releases/tag/19.1.0&quot;&gt;
    &lt;img class=&quot;img-fluid&quot; style=&quot;max-width: 60%&quot; src=&quot;/assets/images/angular_gradient.webp&quot; alt=&quot;Angular logo&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;This is a minor release with some nice features: let&amp;#39;s dive in!&lt;/p&gt;
&lt;h2&gt;TypeScript 5.7 support&lt;/h2&gt;
&lt;p&gt;Angular v19.1 now supports TypeScript 5.7.
This means that you can use the latest version of TypeScript in your Angular applications.
You can check out the &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-7/&quot;&gt;TypeScript 5.7 release notes&lt;/a&gt;
to learn more about the new features.&lt;/p&gt;
&lt;h2&gt;Automatic removal of unused standalone imports&lt;/h2&gt;
&lt;p&gt;Since &lt;a href=&quot;/2024/11/19/what-is-new-angular-19.0/&quot;&gt;Angular v19.0&lt;/a&gt;,
there is an extended diagnostic that warns you
if you import a standalone component, or pipe, or directive,
but don&amp;#39;t actually use it (making this import unnecessary).
Angular v19.1 goes further:
it provides a schematic that removes all those unnecessary imports for you.
You simply need to execute &lt;code&gt;ng generate @angular/core:cleanup-unused-imports&lt;/code&gt;
to clean all your imports.&lt;/p&gt;
&lt;h2&gt;NgComponentOutlet&lt;/h2&gt;
&lt;p&gt;You know it&amp;#39;s not a big release when one of the most interesting feature
is a new property on a not-very-often-used directive.
But here it is: the &lt;code&gt;ngComponentOutlet&lt;/code&gt; directive now has a &lt;code&gt;componentInstance&lt;/code&gt; property,
allowing to access the instance of the component created by the directive.
The directive is now also exposed as &lt;code&gt;ngComponentOutlet&lt;/code&gt;, allowing to reference it in templates:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ng-container&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  [ngComponentOutlet]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;component&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  #myDynamicComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ngComponentOutlet&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Devtools&lt;/h2&gt;
&lt;p&gt;The devtools now have a router graph to view the routes that are loaded in the application.&lt;/p&gt;
&lt;p&gt;Some internal work has also been done to add a &amp;quot;tracing&amp;quot; service,
that the framework calls to trace what triggers change detection.
This could be leveraged by the devtools to provide more information
about change detection in the future.&lt;/p&gt;
&lt;p&gt;Another addition in v19.1 is the ability to inspect the signal graph of the application.
Currently, it is a private debug function called &lt;code&gt;ɵgetSignalGraph&lt;/code&gt;
that you can use via &lt;code&gt;window.ng.ɵgetSignalGraph()&lt;/code&gt; in the console if you enable the debug tools.
We can safely bet that this will be exposed in the devtools in the future
with a nice graph showing the signals and their dependencies.&lt;/p&gt;
&lt;h2&gt;Angular CLI&lt;/h2&gt;
&lt;h3&gt;Templates HMR&lt;/h3&gt;
&lt;p&gt;As we hinted in our &lt;a href=&quot;/2024/11/19/what-is-new-angular-19.0/&quot;&gt;v19 blog post&lt;/a&gt;,
the CLI now has HMR for templates enabled by default!&lt;/p&gt;
&lt;p&gt;v19 enabled HMR for styles, and now it&amp;#39;s also enabled for templates in v19.1,
both for inline and external templates.
As for the styles, this required some internal changes in the compiler.
As it is still a fairly new feature,
you may have to manually refresh the page sometimes
or restart your server.
The HMR feature itself can bail out and do a full rebuild,
for example, if too many files were modified (currently 32).
It can be disabled with &lt;code&gt;--hmr=false&lt;/code&gt; or &lt;code&gt;--live-reload=false&lt;/code&gt; in the &lt;code&gt;serve&lt;/code&gt; command,
or by using &lt;code&gt;NG_HMR_TEMPLATES=0&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;i18n subPath&lt;/h3&gt;
&lt;p&gt;It is now easier to specify a customized URL segment for internationalized applications,
like &lt;code&gt;/fr&lt;/code&gt; for French or &lt;code&gt;/es&lt;/code&gt; for Spanish.
It was already possible to use &lt;code&gt;baseHref&lt;/code&gt; in the &lt;code&gt;i18n&lt;/code&gt; configuration,
but it was still necessary to manually put the generated files in the proper sub-directory yourself.
The &lt;code&gt;baseHref&lt;/code&gt; option is now deprecated in favor of &lt;code&gt;subPath&lt;/code&gt;,
which acts as a base href and the name of the folder where the localized version is built:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;locales&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;fr&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;subPath&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;fr&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // can be omitted if it&apos;s the same as the locale&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;translation&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;src/i18n/messages.fr.json&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;es&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;subPath&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;es&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;translation&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;src/i18n/messages.es.json&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The generated files will be in &lt;code&gt;dist/my-app/browser/fr&lt;/code&gt; and &lt;code&gt;dist/my-app/browser/es&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;SSR redirection to preferred locale&lt;/h3&gt;
&lt;p&gt;If your application supports several languages,
the server will now redirect your users to their preferred locales,
based on their browser settings.
This leverages the &lt;code&gt;Accept-Language&lt;/code&gt; header to determine the preferred locales
(ranked by their quality value, for example, &lt;code&gt;en-US;q=0.8,fr-FR;q=0.9&lt;/code&gt;)
and redirect the user to the corresponding URL segment based on the supported locales.
It tries to find the exact locales first, then the locales without the region,
then falls back to first supported locale if none of the previous ones are supported.
This works out of the box without needing to configure anything.&lt;/p&gt;
&lt;h3&gt;SSR preload lazy-loaded routes&lt;/h3&gt;
&lt;p&gt;The CLI now preloads lazy-loaded routes during server-side rendering,
by adding &lt;code&gt;modulepreload&lt;/code&gt; links in the generated HTML.
This is limited to 10 modules
and does not work when the chunk optimization option is enabled
(see our blog post about &lt;a href=&quot;/2024/07/10/what-is-new-angular-18.1/&quot;&gt;Angular v18.1&lt;/a&gt;).&lt;/p&gt;
&lt;h3&gt;ng-packagr builder&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;ng-packagr&lt;/code&gt; package is now available as a builder in the CLI (&lt;code&gt;@angular/build:ng-packagr&lt;/code&gt;)
and can now be used to build libraries.
It is used by default when you create a library with &lt;code&gt;ng generate library&lt;/code&gt;
and removes the need to have the &lt;code&gt;@angular-devkit/build-angular&lt;/code&gt; package installed
as you can see in our &lt;a href=&quot;https://github.com/cexbrayat/angular-cli-library-diff/compare/19.1.0-next.2...19.1.0-rc.0&quot;&gt;angular-cli-library-diff Github repo&lt;/a&gt;
that tracks changes in a generated library.&lt;/p&gt;
&lt;p&gt;Speaking about repositories helping to track differences between CLI versions,
we created a new one for the CLI when generating an application with the &lt;code&gt;--ssr&lt;/code&gt; option:
&lt;a href=&quot;https://github.com/cexbrayat/angular-cli-ssr-diff&quot;&gt;angular-cli-ssr-diff&lt;/a&gt; 🚀
(in addition to the one for &lt;a href=&quot;https://github.com/cexbrayat/angular-cli-library-diff&quot;&gt;libraries&lt;/a&gt;
and the most popular one for &lt;a href=&quot;https://github.com/cexbrayat/angular-cli-diff&quot;&gt;basic CLI applications&lt;/a&gt;).&lt;/p&gt;
&lt;h3&gt;Warning about bad localize import&lt;/h3&gt;
&lt;p&gt;The CLI will now warn you if you import &lt;code&gt;@angular/localize/init&lt;/code&gt; directly in your code:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;Direct&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; import&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; of&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;@angular/localize/init&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; detected.&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; This&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; may&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; lead&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; undefined&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; behavior.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The proper way to add localize is to add it to your polyfills in &lt;code&gt;angular.json&lt;/code&gt;
(as &lt;code&gt;ng add @angular/localize&lt;/code&gt; does).&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;That&amp;#39;s all for this release, stay tuned!&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>What&apos;s new in Angular 19.0?</title>
    <link href="https://blog.ninja-squad.com/2024/11/19/what-is-new-angular-19.0"/>
    <updated>2024-11-19T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2024/11/19/what-is-new-angular-19.0</id>
    <content type="html">
      &lt;p&gt;Angular&amp;nbsp;19.0.0 is here!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;a href=&quot;https://github.com/angular/angular/releases/tag/19.0.0&quot;&gt;
    &lt;img class=&quot;img-fluid&quot; style=&quot;max-width: 60%&quot; src=&quot;/assets/images/angular_gradient.webp&quot; alt=&quot;Angular logo&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;This is a major release with a lot of features.
Components are now standalone by default and most of the new Signal APIs are stable!&lt;/p&gt;
&lt;p&gt;We have been hard at work these past months to completely re-write our 
&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;&amp;quot;Become a Ninja with Angular&amp;quot; ebook&lt;/a&gt;
and &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;our online workshop&lt;/a&gt;
to use signals from the start! 🚀
The update is free if you already have it, as usual 🤗.
I can&amp;#39;t believe we have been maintaining this ebook
and workshop for nearly 10 years.
If you don&amp;#39;t have it already, go grab it now!&lt;/p&gt;
&lt;h2&gt;TypeScript 5.6 support&lt;/h2&gt;
&lt;p&gt;Angular v19 now supports TypeScript 5.6.
This means that you can use the latest version of TypeScript in your Angular applications.
You can check out the &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-6/&quot;&gt;TypeScript 5.6 release notes&lt;/a&gt; 
to learn more about the new features.
TypeScript 5.4 is no longer supported.&lt;/p&gt;
&lt;h2&gt;Standalone by default&lt;/h2&gt;
&lt;p&gt;We no longer need to add &lt;code&gt;standalone: true&lt;/code&gt; in the component/directive/pipe decorator,
as it is now the default behavior!&lt;/p&gt;
&lt;p&gt;A migration will take care of removing it for you when running &lt;code&gt;ng update&lt;/code&gt;,
and add &lt;code&gt;standalone: false&lt;/code&gt; to your non-standalone entities if needed.&lt;/p&gt;
&lt;p&gt;If you want to make sure all your components are standalone,
you can use the new &lt;code&gt;&amp;quot;strictStandalone&amp;quot;: true&lt;/code&gt; option in the &lt;code&gt;angularCompilerOptions&lt;/code&gt;.
If that&amp;#39;s not the case, you&amp;#39;ll see:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;TS&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;992023&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: Only standalone components&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;directives are allowed when &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;strictStandalone&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; is enabled&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Unused imports in standalone components&lt;/h2&gt;
&lt;p&gt;A wonderful extended diagnostic has been added to the Angular compiler,
allowing it to detect unused imports in standalone components!&lt;/p&gt;
&lt;p&gt;This is a great addition, as it will help you to keep your components clean and tidy.
If you forget to remove an import after refactoring your code,
you&amp;#39;ll see a message like this:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;TS-998113: Imports array contains unused imports [plugin angular-compiler]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;src/app/user/users.component.ts:9:27:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  9 │   imports: [UserComponent, UnusedComponent],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ╵                            ~~~~~~~~~~~~~~~&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A code action is provided to remove the unused import for you via the language service
(but there is no automatic migration doing it for you, unfortunately).&lt;/p&gt;
&lt;p&gt;You can disable the diagnostic if needed with:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;extendedDiagnostics&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;checks&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;unusedStandaloneImports&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;suppress&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Signal APIs are stable (well, most of them)&lt;/h2&gt;
&lt;p&gt;Most of the Signal APIs (and RxJS interoperability functions) are no longer in developer preview
and can safely be used.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;input()&lt;/code&gt;, &lt;code&gt;output()&lt;/code&gt;, &lt;code&gt;model()&lt;/code&gt;, &lt;code&gt;viewChild()&lt;/code&gt;, &lt;code&gt;viewChildren()&lt;/code&gt;,
&lt;code&gt;contentChild&lt;/code&gt;, &lt;code&gt;contentChildren()&lt;/code&gt;, &lt;code&gt;takeUntilDestroyed()&lt;/code&gt;, &lt;code&gt;outputFromObservable()&lt;/code&gt;,
and &lt;code&gt;outputToObservable()&lt;/code&gt; are now marked as stable.&lt;/p&gt;
&lt;p&gt;Of course, migrating complete applications to these new APIs can be a bit of work.
But you know what, the Angular team cooked some automatic migrations! 😍
We will talk about them in the next section.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;effect&lt;/code&gt; went through some changes and is still in developer preview.
&lt;code&gt;toObservable&lt;/code&gt; (which uses an effect) and &lt;code&gt;toSignal&lt;/code&gt; are still in developer preview as well.&lt;/p&gt;
&lt;p&gt;All effects aren&amp;#39;t handled the same way anymore.
Angular distinguishes two kinds of effects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;component effects, which are created in components or directives;&lt;/li&gt;
&lt;li&gt;root effects, which are created in root services, or with the &lt;code&gt;forceRoot&lt;/code&gt; option.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Component effects now run &lt;em&gt;during&lt;/em&gt; change detection
(just before the actual change detection of their owning component)
and not &lt;em&gt;after&lt;/em&gt; it as it was the case before.
This is a breaking change.
You might thus see some changes in their behavior,
for example when an effect is triggered by a change of a view query signal.
To solve this case, a new &lt;code&gt;afterRenderEffect&lt;/code&gt; function has been added.
It is similar to &lt;code&gt;effect&lt;/code&gt;, but its function runs after the rendering rather than before.
Like &lt;code&gt;afterRender&lt;/code&gt; and &lt;code&gt;afterNextRender&lt;/code&gt;
(check our &lt;a href=&quot;/2023/08/09/what-is-new-angular-16.2/&quot;&gt;blog post&lt;/a&gt; if you need a refresher), 
it can also specify what should be executed in each rendering phase
but values are propagated from phase to phase as signals instead of as plain values.
As a result, later phases may not need to execute
if the values returned by earlier phases do not change.
All these &lt;code&gt;afterRender&lt;/code&gt; functions are still in developer preview.&lt;/p&gt;
&lt;p&gt;Root effects are not tied to a component lifecycle
and are usually used to synchronize the state of the application
with the outside world
(for example, to write it to the local storage).
These effects don&amp;#39;t run as part of the change detection but as a microtask
(and can be triggered in tests using &lt;code&gt;TestBed.flushEffects()&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Another notable change is that you can now write to signals in effects,
without the need to specify the (now deprecated) option &lt;code&gt;allowSignalWrites: true&lt;/code&gt;.
The team found out that it was not preventing basic usages
but was just making the code more verbose when really needed.&lt;/p&gt;
&lt;p&gt;All in all, effects should be stabilized in the next release.
However their usage is still not recommended for most cases,
and it seems like they should be the last resort to solve a problem.
That&amp;#39;s why the framework introduced the new experimental functions &lt;code&gt;linkedSignal&lt;/code&gt;,
&lt;code&gt;resource&lt;/code&gt;, and &lt;code&gt;rxResource&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Linked signals with linkedSignal()&lt;/h2&gt;
&lt;p&gt;Angular v19 introduced a new (developer preview) concept called &amp;quot;linked signals&amp;quot;.
A linked signal is a &lt;em&gt;writable&lt;/em&gt; signal,
but it is also a &lt;em&gt;computed&lt;/em&gt; signal,
as its content can be reset thanks to a computation that depends on another signal (or several ones).&lt;/p&gt;
&lt;p&gt;Imagine we have a component that displays a list of items received via an input,
and we want our users to select one of them.
By default, let’s say we want to select the first item of the list.
But every time the list of items changes,
the selected item may no longer be valid,
so we want to reset the selected item to the first one.&lt;/p&gt;
&lt;p&gt;We can imagine a component like this:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ItemListComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt; items&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ItemModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt; selectedItem&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; signal&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ItemModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; undefined&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;undefined&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  pickItem&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;item&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ItemModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;selectedItem&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;item&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using an effect may come to mind to solve the selection problem:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;constructor&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // ⚠️ This is not recommended&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  effect&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;selectedItem&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;items&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()[&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every time the list of items changes,
the effect will be triggered and the first item will be selected.&lt;/p&gt;
&lt;p&gt;There is a nice trick that I can show you before we dive into the now-recommended solution:
we can use a computed value that returns…​ a signal!&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ItemListComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  items&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ItemModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  selectedItem&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; computed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;WritableSignal&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ItemModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; undefined&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; signal&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;items&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()[&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  )&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  pickItem&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;item&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ItemModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    this.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;selectedItem&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;item&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the computed value returns a signal that represents the selected item
(whereas they usually return a value directly).
Every time the list of items changes, the computed function is re-evaluated,
and returns a new signal that represents the selected item.
The downside of this solution is that we have to use &lt;code&gt;selectedItem()()&lt;/code&gt; to read the value,
or &lt;code&gt;selectedItem().set()&lt;/code&gt; to update it, which is a bit ugly.&lt;/p&gt;
&lt;p&gt;This is where we can use a &lt;code&gt;linkedSignal&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ItemListComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  items&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ItemModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // ✅ This is recommended&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  selectedItem&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; WritableSignal&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ItemModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; linkedSignal&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;items&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()[&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;linkedSignal&lt;/code&gt; is a &lt;code&gt;WritableSignal&lt;/code&gt;,
but its value can be reset thanks to a computation.
If the items change, then the computation will be re-executed
and the value of the signal will be updated with the result.&lt;/p&gt;
&lt;p&gt;The computation can of course depend on several signals.
Here &lt;code&gt;selectedItem&lt;/code&gt; is reset when the items input changes,
but also when the enabled input changes.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ItemListComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  items&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ItemModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  enabled&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // recomputes if `enabled` or `items` change&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  selectedItem&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; linkedSignal&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;enabled&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;items&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()[&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; undefined&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that you can use the previous value of the source signal in the computation function if you need to.
For example, if you want to access the previous items value to compare it with the new one,
you can declare the &lt;code&gt;linkedSignal&lt;/code&gt; with the source and computation options.
In that case, the computation function receives the current and previous values of the source as parameters.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ItemListComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  items&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ItemModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  selectedItem&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; linkedSignal&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;/* source */&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;ItemModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; /* value */&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; ItemModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    source&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;items&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    computation&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (items&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; previous) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;      // pick the item the user selected if it&apos;s still in the new item list&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      if&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;previous&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; !== &lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;undefined&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; previousChoice&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; previous&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // previous.source contains the previous items&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;items&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;item&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; item&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;includes&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;previousChoice&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;          return&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; previousChoice&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;      return items&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt; });&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Async resources with resource() and rxResource()&lt;/h2&gt;
&lt;p&gt;Most applications need to fetch data from a server, depending on some parameters,
and display the result in the UI: &lt;code&gt;resource&lt;/code&gt; aims to help with that.&lt;/p&gt;
&lt;p&gt;This API is experimental, and will go through an RFC process soon:
I would not advise you to use it yet.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;resource&lt;/code&gt; function takes an object with a mandatory loader function that returns a promise:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;list&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(): ResourceRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;UserModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; undefined&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  return &lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;resource&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  loader&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;    const response &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; fetch&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;/users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      return&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; response.json(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) as &lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;UserModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  })&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This example doesn’t use the HTTP client, but the native &lt;code&gt;fetch()&lt;/code&gt; function, which returns a promise.
Indeed, the &lt;code&gt;resource()&lt;/code&gt; function is not linked to RxJS,
and can thus use any client that returns promises.
&lt;code&gt;rxResource&lt;/code&gt;, which we will discuss in a few seconds,
is the alternative to &lt;code&gt;resource&lt;/code&gt; that can be used with an Observable-based client.
This is another example of Angular decoupling itself from RxJS,
but still providing interoperability functions allowing you to use it smoothly.&lt;/p&gt;
&lt;p&gt;The function returns a &lt;code&gt;ResourceRef&lt;/code&gt;, an object containing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;an &lt;code&gt;isLoading&lt;/code&gt; signal that indicates if the resource is loading;&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;value&lt;/code&gt; signal that contains the result of the promise;&lt;/li&gt;
&lt;li&gt;an &lt;code&gt;error&lt;/code&gt; signal that contains the error if the promise is rejected;&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;status&lt;/code&gt; signal that contains the status of the resource.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can then use these signals in your template:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (usersResource&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;isLoading&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Loading...&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; @else&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  @for&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (user &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; usersResource&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; track&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;id) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;status&lt;/code&gt; signal can be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ResourceStatus.Idle&lt;/code&gt;, the initial state;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ResourceStatus.Loading&lt;/code&gt;, when the promise is pending;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ResourceStatus.Error&lt;/code&gt;, when the promise is rejected;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ResourceStatus.Resolved&lt;/code&gt;, when the promise is resolved;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ResourceStatus.Reloading&lt;/code&gt;, when the resource is reloading;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ResourceStatus.Local&lt;/code&gt;, when the value is set locally.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The resource also has a &lt;code&gt;reload&lt;/code&gt; method that allows you to reload the resource.
In that case, its status will be set to &lt;code&gt;ResourceStatus.Reloading&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But the reloading can also be automatic, thanks to the &lt;code&gt;request&lt;/code&gt; option.
When provided, the resource will automatically reload if one of the signals used in the request changes.
Here, for example, the component has a &lt;code&gt;sortOrder&lt;/code&gt; option that is used in the request:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;sortOrder &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; signal&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;asc&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;desc&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;asc&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;usersResource &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; resource&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇 The `sortOrder` signal is used to trigger a reload&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  request&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; sort&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;sortOrder&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  loader&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; params&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // 👇 Params also contains the `abortSignal` to cancel the request&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // and the previous status of the resource&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // here we are only interested in the request&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; request&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; params&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;request&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; response&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; fetch&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;/users?sort=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;request&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;sort&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; response&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;UserModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the &lt;code&gt;sortOrder&lt;/code&gt; signal changes,
the resource will automatically reload!
You can also cancel the previous request if needed when the resource is reloaded
using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal&quot;&gt;&lt;code&gt;abortSignal&lt;/code&gt;&lt;/a&gt; parameter of the loader
(for example to implement a debounce).
You can choose to ignore the reload request
and thus keep the current value by returning &lt;code&gt;undefined&lt;/code&gt; from the request function.&lt;/p&gt;
&lt;p&gt;Last but not least, the returned &lt;code&gt;ResourceRef&lt;/code&gt; is in fact writable.
You can use its &lt;code&gt;set&lt;/code&gt; or &lt;code&gt;update&lt;/code&gt; methods to change the value of the resource
(on the &lt;code&gt;value&lt;/code&gt; or on the resource itself, both work).
In that case, its status will be set to &lt;code&gt;ResourceStatus.Local&lt;/code&gt;.
If you’re only interested in reading the resource,
you can use the &lt;code&gt;asReadonly&lt;/code&gt; method to get a read-only version of the resource.&lt;/p&gt;
&lt;p&gt;Finally, the &lt;code&gt;ResourceRef&lt;/code&gt; has a destroy method that can be used to stop the resource.&lt;/p&gt;
&lt;p&gt;Now, let’s see how we can use an observable-based resource instead of a promised-based one.&lt;/p&gt;
&lt;p&gt;You can use the &lt;code&gt;rxResource()&lt;/code&gt; function in that case.
This function is really similar to &lt;code&gt;resource()&lt;/code&gt;,
but its loader must return an observable instead of a promise.
This allows you to use our good old &lt;code&gt;HttpClient&lt;/code&gt; service to fetch data from a server,
using all your interceptors, error handling, etc:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;sortOrder &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; signal&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;asc&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;desc&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;asc&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;usersResource &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; rxResource&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  request&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; sort&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;sortOrder&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇 RxJS powered loader&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  loader&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ({&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; request&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; })&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;httpClient&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;UserModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;/users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; params&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; sort&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; request&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;sort &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that the &lt;code&gt;rxResource()&lt;/code&gt; function is from the &lt;code&gt;@angular/core/rxjs-interop package&lt;/code&gt;,
where the &lt;code&gt;resource()&lt;/code&gt; function is from &lt;code&gt;@angular/core&lt;/code&gt;.
Another noteworthy detail is that only the first value of the observable is taken into account,
so you can’t have a stream of values.&lt;/p&gt;
&lt;p&gt;Some of you may get a feeling of déjà vu with all this,
as it’s quite similar to the &lt;a href=&quot;https://tanstack.com/query/&quot;&gt;TanStack Query&lt;/a&gt; library.
I must insist that this is experimental and will probably evolve in the future.
It will also probably be used by higher-level APIs or libraries.
Let’s see what the RFC process will bring us!&lt;/p&gt;
&lt;h2&gt;Automatic migration for signals&lt;/h2&gt;
&lt;p&gt;Now that signal inputs, view queries and content queries are stable,
why not refactor all our components to use them?
That can be automated using the following migration:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ng generate @angular/core:signals&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;? Which migrations do you want to run? (Press &amp;#x3C;space&gt; to select, &amp;#x3C;a&gt; to toggle all, &amp;#x3C;i&gt; to invert selection, and &amp;#x3C;enter&gt; to proceed)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;❯◉ Convert `@Input` to the signal-based `input`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; ◉ Convert `@Output` to the new `output` function&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; ◉ Convert `@ViewChild`/`@ViewChildren` and `@ContentChild`/`@ContentChildren` to the signal-based `viewChild`/`viewChildren` and&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;`contentChild`/`contentChildren`&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can then choose which directory you want to migrate (all the application by default).
The migration, by default, is conservative.
If it can&amp;#39;t migrate something without breaking the build, it will leave it as it is.
But you can be more aggressive by passing the option &lt;code&gt;--best-effort-mode&lt;/code&gt; as we&amp;#39;ll see.
For a complete list of options, run &lt;code&gt;ng generate @angular/core:signals --help&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After the migration, a report is displayed,
showing how many inputs/outputs/viewChildren/contentChildren have been migrated.
If you picked the less aggressive option, some of them might not have been migrated,
and you can re-run the migration with &lt;code&gt;--insert-todos&lt;/code&gt;
to add explanation comments in the code where the migration couldn&amp;#39;t be done.&lt;/p&gt;
&lt;p&gt;For example, an &lt;code&gt;@Input&lt;/code&gt; used on a setter yields the following TODO:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// TODO: Skipped for migration because:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;//  Accessor inputs cannot be migrated as they are too complex.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another example that you&amp;#39;ll encounter fairly often is when an &lt;code&gt;@Input&lt;/code&gt; is used in a template inside an &lt;code&gt;@if&lt;/code&gt;,
the migration can&amp;#39;t update it due to type-narrowing issues:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// TODO: Skipped for migration because:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;//  This input is used in a control flow expression (e.g. `@if` or `*ngIf`)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;//  and migrating would break narrowing currently.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These incompatibility reasons can then be migrated with the more aggressive option &lt;code&gt;--best-effort-mode&lt;/code&gt;,
but you&amp;#39;ll probably have to fix some errors manually.&lt;/p&gt;
&lt;p&gt;The migration works astonishingly well, and you can then enjoy the new Signal APIs!
Of course, it does not refactor the code to use &lt;code&gt;computed&lt;/code&gt; instead of &lt;code&gt;ngOnChanges&lt;/code&gt; or other patterns that could be used with signals,
but it&amp;#39;s a good start and will save you a lot of time.&lt;/p&gt;
&lt;p&gt;You should also be able to trigger the migration for a specific file or property from your IDE with the new version of the language service!&lt;/p&gt;
&lt;p&gt;After running these migrations on a few projects,
my advice would be to first run the &lt;code&gt;outputs&lt;/code&gt; one,
as it is fairly trivial.&lt;/p&gt;
&lt;p&gt;Then you can run the &lt;code&gt;queries&lt;/code&gt; one,
which is a bit more complex but still quite safe
(with a few possible incompatible cases).
Finally, you can run the &lt;code&gt;inputs&lt;/code&gt; one,
which is the most complex and may require manual intervention.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ng generate @angular/core:signals --migrations=outputs --defaults&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ng generate @angular/core:signals --migrations=queries --defaults&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ng generate @angular/core:signals --migrations=inputs --defaults&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can then lint, build, and test your application to see if everything is still working as expected.
You can then re-run the migration with &lt;code&gt;--insert-todos&lt;/code&gt; to see the reasons why some fields have been skipped.
Then you can re-run the migration with &lt;code&gt;--best-effort-mode&lt;/code&gt; to try to migrate them anyway.&lt;/p&gt;
&lt;h2&gt;provideAppInitializer instead of APP_INITIALIZER&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;APP_INITIALIZER&lt;/code&gt; token is now deprecated in favor of &lt;code&gt;provideAppInitializer&lt;/code&gt;.
This new function is a more elegant way to provide an initializer to your application.&lt;/p&gt;
&lt;p&gt;Before v19, you would provide an initializer like this:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;  provide&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; APP_INITIALIZER&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;  useValue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; inject&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;InitService&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;  multi&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;},&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you need to use &lt;code&gt;provideAppInitializer&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;provideAppInitializer&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; inject&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(InitService)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;())&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;ENVIRONMENT_INITIALIZER&lt;/code&gt; and &lt;code&gt;PLATFORM_INITIALIZER&lt;/code&gt; Are also deprecated in favor of &lt;code&gt;provideEnvironmentInitializer&lt;/code&gt; and &lt;code&gt;providePlatformInitializer&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As usual, an automatic migration will take care of this for you when running &lt;code&gt;ng update&lt;/code&gt; (you may have to refactor a bit if you want to have a nice function with &lt;code&gt;inject&lt;/code&gt; as I used in the example above).&lt;/p&gt;
&lt;h2&gt;Templates&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;@let&lt;/code&gt; syntax, introduced in &lt;a href=&quot;/2024/07/10/what-is-new-angular-18.1/&quot;&gt;Angular v18.1&lt;/a&gt;, is now stable.&lt;/p&gt;
&lt;p&gt;Expressions in the template can now use the &lt;code&gt;typeof&lt;/code&gt; operator,
so you can write things like &lt;code&gt;@if (typeof user === &amp;#39;object&amp;#39;) {&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;keyvalue&lt;/code&gt; pipe also has a new option.
This pipe has been around for a long time
and allows you to iterate over the entries of an object.
But it, perhaps surprisingly, orders the entries by their key by default,
as we explained in our &lt;a href=&quot;/2018/07/26/what-is-new-angular-6.1/&quot;&gt;Angular 6.1 blog post (back in 2018 😅)&lt;/a&gt;.
You could already pass a comparator function,
but you can now pass &lt;code&gt;null&lt;/code&gt; to disable the ordering:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@for&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (entry &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; userModel&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; keyvalue&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;null;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; track&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; entry&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;key) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; entry&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;key &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; entry&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Router&lt;/h2&gt;
&lt;p&gt;It is now possible to pass data to a &lt;code&gt;RouterOutlet&lt;/code&gt;,
making it easy to share data from a parent component to its nested children.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;router-outlet&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [routerOutletData]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;userModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;router-outlet&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then in a child component, you can get the data via DI and the token &lt;code&gt;ROUTER_OUTLET_DATA&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;readonly userModel &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; inject&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;Signal&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;UserModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(ROUTER_OUTLET_DATA)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that, for the first time I believe, the value you get via DI is not a static value, but a signal!
That means that every time &lt;code&gt;userModel&lt;/code&gt; changes in the parent component,
the signal in the child component will be updated as well.&lt;/p&gt;
&lt;h2&gt;Service worker&lt;/h2&gt;
&lt;p&gt;A few features have been added to the service worker support in Angular.&lt;/p&gt;
&lt;p&gt;First, it is now possible to specify a &lt;code&gt;maxAge&lt;/code&gt; for the entire application,
via a new configuration option called &lt;code&gt;applicationMaxAge&lt;/code&gt;.
This allows us to configure how long the service worker will cache any requests.
Within the &lt;code&gt;applicationMaxAge&lt;/code&gt;, files will be served from the cache.
Beyond that, all requests will only be served from the network.
This can be particularly useful for the &lt;code&gt;index.html&lt;/code&gt; file,
to make sure a user returning several months later
will get the latest version of the application and not an old cached version.
You can define the &lt;code&gt;applicationMaxAge&lt;/code&gt; in the &lt;code&gt;ngsw-config.json&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;applicationMaxAge&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;1d6h&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; // 1 day and 6 hours&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another new feature is the ability to define a &lt;code&gt;refreshAhead&lt;/code&gt;
delay for a specific data group. 
When the time before the expiration of a cached resource is less than this &lt;code&gt;refreshAhead&lt;/code&gt; delay,
Angular refreshes the resource.
Fun fact: this feature was already implemented,
but not publicly exposed.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;dataGroups&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;api-users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;urls&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;/api/users/**&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;cacheConfig&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;        &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;maxAge&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;1d&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;        &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;timeout&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;10s&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;        &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;refreshAhead&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;10m&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;SSR&lt;/h2&gt;
&lt;p&gt;There are tons of changes in the Server-Side Rendering (SSR) part of Angular,
both in the framework and in the CLI.&lt;/p&gt;
&lt;h3&gt;Event Replay is stable&lt;/h3&gt;
&lt;p&gt;The event replay feature, introduced in &lt;a href=&quot;/2024/05/22/what-is-new-angular-18.0/&quot;&gt;Angular v18&lt;/a&gt;, is now stable.
The CLI will now generate the necessary &lt;code&gt;withEventReplay()&lt;/code&gt; call for you
when you create a new application with SSR.&lt;/p&gt;
&lt;h3&gt;Application stability&lt;/h3&gt;
&lt;p&gt;When working with SSR, Angular needs to know when the application is stable,
meaning that all the asynchronous operations have been completed,
in order to render the application to a string and send it to the client.
Zone.js usually allows knowing this but in a zoneless application,
you need to do it yourself.&lt;/p&gt;
&lt;p&gt;Angular does the bulk of the work for you,
by internally keeping track of the asynchronous operations it triggers
(an HTTP request done via the &lt;code&gt;HttpClient&lt;/code&gt;, for example),
using a service called &lt;code&gt;PendingTasks&lt;/code&gt;.
It has been renamed from &lt;code&gt;ExperimentPendingTasks&lt;/code&gt; and stabilized in v19,
and an automatic migration will take care of this renaming for you during &lt;code&gt;ng update&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can also use &lt;code&gt;PendingTasks&lt;/code&gt; in your application to track your own asynchronous operations.
The service has an &lt;code&gt;add&lt;/code&gt; method to manually create a task that you can later clean,
but a &lt;code&gt;run&lt;/code&gt; method has been added for convenience in v19,
allowing you to directly pass an async function:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; userData &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; inject&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(PendingTasks)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; fetch&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;/api/users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;//☝️ Angular will wait for the promise to resolve&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(usersData)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A new (experimental) RxJS operator called &lt;code&gt;pendingUntilEvent&lt;/code&gt;
has also been added to the framework (in the &lt;code&gt;@angular/core/rxjs-interop&lt;/code&gt; package):
it allows marking an observable as important for the application stability until a first event is emitted:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;users &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; toSignal&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(users$&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;pipe&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;pendingUntilEvent&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Partial and incremental hydration&lt;/h3&gt;
&lt;p&gt;Building upon the event replay feature,
and the &lt;code&gt;@defer&lt;/code&gt; feature (check &lt;a href=&quot;/2023/11/02/angular-defer/&quot;&gt;our blog post&lt;/a&gt; if you need a refresher),
the Angular team has introduced a new feature called 
&lt;a href=&quot;https://github.com/angular/angular/discussions/57664&quot;&gt;&amp;quot;incremental hydration&amp;quot;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With incremental hydration, deferred content is rendered on the server side
(instead of rendering the defer placeholder),
but skipped over during client-side hydration
(it&amp;#39;s left dehydrated, hence the &amp;quot;partial hydration&amp;quot; concept).&lt;/p&gt;
&lt;p&gt;It means that the application is fully rendered,
but some parts are not yet interactive when the application bootstraps.
When a user interacts with a dehydrated component,
Angular will download the necessary code and hydrate the component
(and its perhaps dehydrated parent components) on the fly,
then replay the events that happened while the component was dehydrated,
leaving the impression that the component was already active 🤯.&lt;/p&gt;
&lt;p&gt;This feature is in developer preview in v19,
and can be activated with &lt;code&gt;withIncrementalHydration()&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;bootstrapApplication&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(AppComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  providers&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;provideClientHydration&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;withIncrementalHydration&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;())]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The syntax to enable it is quite simple and uses the &lt;code&gt;@defer&lt;/code&gt; block
with an additional &lt;code&gt;hydrate&lt;/code&gt; option to define the hydration condition.
The possible hydration triggers are the same as the &lt;code&gt;@defer&lt;/code&gt; conditions
(that we explained in detail in the blog post mentioned above).&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@defer&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(on &lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;timer&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(15s)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; hydrate on interaction) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;app-users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; @placeholder&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Loading&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Until v19, the loading placeholder would be rendered in SSR.
With the &lt;code&gt;withIncrementalHydration()&lt;/code&gt; option,
the &lt;code&gt;UsersComponent&lt;/code&gt; will be rendered, but not hydrated on the client.&lt;/p&gt;
&lt;p&gt;For example, the DOM will look like:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;app-users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  &amp;#x3C;!-- Dehydrated content --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; jsaction&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;click:;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Refresh users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  &amp;#x3C;!-- more content --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;app-users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the user clicks on the button,
Angular will download the necessary code for the &lt;code&gt;UsersComponent&lt;/code&gt;,
then hydrate it and replay the events that happened
while the component was dehydrated (here, refreshing the list of users).&lt;/p&gt;
&lt;p&gt;This is a powerful feature
for those who are looking to improve the performance of their applications,
and it highlights the flexibility of the control flow syntax in Angular.&lt;/p&gt;
&lt;h3&gt;Route configuration for hybrid rendering&lt;/h3&gt;
&lt;p&gt;Until now, an SSR application with pre-render was pre-rendering the pages with no parameters but ignored parameterized pages.
In v19, &lt;a href=&quot;https://github.com/angular/angular/discussions/56785&quot;&gt;after an RFC&lt;/a&gt;,
the CLI team introduced a new feature called &amp;quot;hybrid rendering&amp;quot;.&lt;/p&gt;
&lt;p&gt;All this work is part of the ongoing effort to improve the SSR experience in Angular,
which includes new APIs (App Engine APIs).&lt;/p&gt;
&lt;p&gt;It is now possible to define the rendering mode per route of the application.
Instead of adding options to the existing route configuration,
the team decided to add a configuration file,
dedicated to the server-side,
which defines the rendering mode for each route.&lt;/p&gt;
&lt;p&gt;Three rendering modes are available:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;RenderMode.Prerender&lt;/code&gt; for pre-rendering the page at build time;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RenderMode.Server&lt;/code&gt; for rendering the page on the server;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RenderMode.Client&lt;/code&gt; for rendering the page on the client.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example, let&amp;#39;s say you have the following routes in your application:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; routes&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; Routes&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // Home component&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; path&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; component&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; HomeComponent &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // About component&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; path&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;about&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; component&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; AboutComponent &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // User component with a parameter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; path&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;users/:id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; component&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; UserComponent &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In v18, &lt;code&gt;ng build&lt;/code&gt; generated a &lt;code&gt;browser&lt;/code&gt; folder with &lt;code&gt;index.html&lt;/code&gt; and &lt;code&gt;about/index.html&lt;/code&gt; files.
In v19, the same configuration throws with:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;✘ [ERROR] The &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;users/:id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; route uses prerendering and includes parameters&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; but &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;getPrerenderParams&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; is missing&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Please define &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;getPrerenderParams&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; route&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; your&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; server&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; routing&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; configuration&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; or&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; specify&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; a&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; different&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;renderMode&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;&apos;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This means there are 2 solutions.
First, we can add a server routing configuration file, &lt;code&gt;app.routes.server.ts&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This file is now generated in a project when using &lt;code&gt;ng new --ssr --server-routing&lt;/code&gt; or &lt;code&gt;ng add @angular/ssr --server-routing&lt;/code&gt;.
The &lt;code&gt;--server-routing&lt;/code&gt; option enables both the server routing configuration and the new App Engine APIs
(all these APIs are in developer preview for now).
It also uses a new option in &lt;code&gt;angular.json&lt;/code&gt; called &lt;code&gt;outputMode&lt;/code&gt; to define the output mode of the application:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;server&lt;/code&gt; generates a server bundle, enabling server-side rendering (SSR) and hybrid rendering strategies.
 This mode is intended for deployment on a Node.js server or a serverless environment. &lt;/li&gt;
&lt;li&gt;&lt;code&gt;static&lt;/code&gt; generates a static output suitable for deployment on static hosting services or CDNs.
 This mode supports both client-side rendering (CSR) and static site generation (SSG).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;ng add @angular/ssr --server-routing&lt;/code&gt; sets the &lt;code&gt;outputMode&lt;/code&gt; to &lt;code&gt;server&lt;/code&gt; by default.
Note that the &lt;code&gt;prerender&lt;/code&gt; and &lt;code&gt;appShell&lt;/code&gt; options are no longer used if you define the &lt;code&gt;outputMode&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s define the server routes configuration for the previous example:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; serverRoutes&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ServerRoute&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    path&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    renderMode&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; RenderMode&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Prerender&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    path&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;about&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    renderMode&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; RenderMode&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Server&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    path&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    renderMode&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; RenderMode&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Client&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This file is then loaded in the &lt;code&gt;app.config.server.ts&lt;/code&gt; file,
using &lt;code&gt;provideServerRoutesConfig(serverRoutes)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The server routes configuration doesn&amp;#39;t need to define all the routes as you can see,
with a possible &amp;quot;catch-all&amp;quot; route &amp;#39;**&amp;#39; to define a default behavior.
If a route doesn&amp;#39;t exist though, you&amp;#39;ll get an error at build time:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;✘ [ERROR] The &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;unknown&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; server route does not match any routes defined &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; the Angular routing &lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;configuration&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (typically provided &lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; a&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; part&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; of&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; the&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;provideRouter&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; call&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Please make sure that the mentioned server route is present &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; the Angular routing configuration&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The second solution is to define a &lt;code&gt;getPrerenderParams&lt;/code&gt; function, to prerender routes with parameters.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;  path&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;users/:id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;  renderMode&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; RenderMode&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Prerender&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  async&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; getPrerenderParams&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(): &lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Record&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // API call to get the user IDs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    const &lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;userIds&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; inject&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;UserService&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;getUserIds&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(); &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // build an array like [{ id: &apos;1&apos; }, { id: &apos;2&apos; }, { id: &apos;3&apos; }]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    return userIds.map(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;},&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will prerender the &lt;code&gt;users/:id&lt;/code&gt; route for each user ID found by the &lt;code&gt;UserService&lt;/code&gt;,
generating &lt;code&gt;users/1/index.html&lt;/code&gt;, &lt;code&gt;users/2/index.html&lt;/code&gt;, etc.&lt;/p&gt;
&lt;p&gt;A really nice change is that &lt;code&gt;server.ts&lt;/code&gt; is now used during prerendering,
allowing access to locally defined API routes.
&lt;code&gt;server.ts&lt;/code&gt; is now also used by the Vite server during development!
If needed you can disable it with the &lt;code&gt;--no-server&lt;/code&gt; option, for example,
to make a static build: &lt;code&gt;ng build --output-mode static --no-server&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As you may not want to prerender all the user pages, you can also define a &lt;code&gt;fallback&lt;/code&gt; option,
that can be &lt;code&gt;PrerenderFallback.Client&lt;/code&gt; (falls back to CSR),
&lt;code&gt;PrerenderFallback.Server&lt;/code&gt; (falls back to SSR),
or &lt;code&gt;PrerenderFallback.None&lt;/code&gt; (the server will not handle the request).&lt;/p&gt;
&lt;p&gt;When using the &lt;code&gt;RenderMode.Server&lt;/code&gt; mode,
you can also define a &lt;code&gt;status&lt;/code&gt; and &lt;code&gt;headers&lt;/code&gt; options to customize the response:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;  path&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;404&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;  renderMode&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; RenderMode&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Server&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;  status&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 404&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;  headers&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Cache-Control&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;no-cache&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also define which route should serve as the app shell of the application
(see the &lt;a href=&quot;https://angular.dev/ecosystem/service-workers/app-shell&quot;&gt;App shell pattern&lt;/a&gt; in the Angular documentation),
by setting the &lt;code&gt;appShellRoute&lt;/code&gt; option: &lt;code&gt;provideServerRoutesConfig(serverRoutes, { appShellRoute: &amp;#39;shell&amp;#39; })&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &amp;quot;App Engine APIs&amp;quot; mentioned earlier are a set of APIs
that allow you to interact with the server-side rendering process,
based on the new &lt;code&gt;AngularAppEngine&lt;/code&gt; and its node version &lt;code&gt;AngularNodeAppEngine&lt;/code&gt;.
They are used in the generated &lt;code&gt;server.ts&lt;/code&gt; file:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;createNodeRequestHandler&lt;/code&gt; allows you to create a request handler for the server-side rendering process
 You can pass it the handler you want to use like an &lt;a href=&quot;http://expressjs.com/&quot;&gt;Express&lt;/a&gt; app,
 which is still the default used when using &lt;code&gt;ng add @angular/ssr&lt;/code&gt;,
 or another like &lt;a href=&quot;https://fastify.dev/&quot;&gt;Fastify&lt;/a&gt;, &lt;a href=&quot;https://hono.dev/&quot;&gt;Hono&lt;/a&gt;, etc.
 This should make it simpler to use a different server framework than Express.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;writeResponseToNodeResponse&lt;/code&gt; allows you to write the response from your server of choice to the node response object.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All these functions aim to make the interactions easier between Node.js
and the framework you picked to handle the requests to your Angular application.
This should provide greater flexibility compared to the previous APIs,
and make it easier to deploy Node.js applications, whatever the server framework you want to use.
And you can build your own variants of &lt;code&gt;AngularAppEngine&lt;/code&gt; to fit your needs for other platforms.&lt;/p&gt;
&lt;p&gt;The CLI team also wants to make it easier to target other runtimes than Node.js.
That&amp;#39;s why a new option &lt;code&gt;ssr.experimentalPlatform&lt;/code&gt; has been added, which lets you define the platform you want to target:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;node&lt;/code&gt; (default) generates a bundle optimized for Node.js;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;neutral&lt;/code&gt; generates a platform-neutral bundle suitable for environments like edge workers, and other serverless platforms that
 do not rely on Node.js APIs.
As the option name indicates, this is an experimental feature.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Request and response via DI&lt;/h3&gt;
&lt;p&gt;It is now easy to access the request and response objects in your components during SSR,
thanks to new DI tokens in &lt;code&gt;@angular/core&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;REQUEST&lt;/code&gt; to access &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Request&quot;&gt;the current HTTP request object&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;REQUEST_CONTEXT&lt;/code&gt; to pass custom metadata or context related to the current request in server-side rendering;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RESPONSE_INIT&lt;/code&gt; to access &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Response/Response&quot;&gt;the response initialization options&lt;/a&gt;;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Angular CLI&lt;/h2&gt;
&lt;p&gt;The CLI has also been released in version v19, with some notable features.&lt;/p&gt;
&lt;p&gt;If you want to upgrade to 19.0.0 without pain (or to any other version, by the way), I have created a Github project to help: &lt;a href=&quot;https://github.com/cexbrayat/angular-cli-diff&quot;&gt;angular-cli-diff&lt;/a&gt;. Choose the version you&amp;#39;re currently using (18.1.0 for example), and the target version (19.0.0 for example), and it gives you a diff of all files created by the CLI: &lt;a href=&quot;https://github.com/cexbrayat/angular-cli-diff/compare/18.1.0...19.0.0&quot;&gt;angular-cli-diff/compare/18.1.0...19.0.0&lt;/a&gt;.
It can be a great help along with the official &lt;code&gt;ng update @angular/core @angular/cli&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s see what&amp;#39;s new in the CLI!&lt;/p&gt;
&lt;h3&gt;Better HMR by default&lt;/h3&gt;
&lt;p&gt;A ton of work has been done to improve the Hot Module Replacement (HMR) experience in Angular.&lt;/p&gt;
&lt;p&gt;When using the &lt;code&gt;application&lt;/code&gt; builder for &lt;code&gt;ng serve&lt;/code&gt;,
HMR is now enabled by default for styles!
This means that when you change a style file (or inline style),
the browser will update the styles without reloading the page
and without rebuilding the application.&lt;/p&gt;
&lt;p&gt;This is sooo nice to see, as you can now change the styles and see the results
in real-time without losing the state of your application.
For example, when working in a modal,
you won&amp;#39;t have to re-open it after each style change!
Definitely a game-changer for day-to-day work.&lt;/p&gt;
&lt;p&gt;The work done in the framework goes even further than that,
and we should be able to have HMR that properly works for templates soon.
It is in fact already possible to try it using &lt;code&gt;NG_HMR_TEMPLATES=1 ng serve&lt;/code&gt;
(this is experimental as you can guess).&lt;/p&gt;
&lt;p&gt;When using this option, the templates will be reloaded,
refreshing all component instances, without reloading the page,
and the state of the application will be preserved!&lt;/p&gt;
&lt;h3&gt;Karma can run with esbuild!&lt;/h3&gt;
&lt;p&gt;Even if Karma is slowly dying,
it is still the default testing solution in newly generated Angular CLI projects.
The Karma integration in Angular was still relying on Webpack until now,
which was a bit sad as all other builders were now using esbuild under the hood.&lt;/p&gt;
&lt;p&gt;This is no longer the case as you can use esbuild with Karma as well!&lt;/p&gt;
&lt;p&gt;To do so, a new option can be used in the Karma builder options in &lt;code&gt;angular.json&lt;/code&gt;:
&lt;code&gt;builderMode&lt;/code&gt;.
This option can have 3 different values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;browser&lt;/code&gt; which is the same as the current behavior, using Webpack under the hood&lt;/li&gt;
&lt;li&gt;&lt;code&gt;application&lt;/code&gt; which uses esbuild&lt;/li&gt;
&lt;li&gt;&lt;code&gt;detect&lt;/code&gt; which uses the same builder as &lt;code&gt;ng serve&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When using &lt;code&gt;application&lt;/code&gt;, you can also remove the &lt;code&gt;@angular-devkit/build-angular/plugins/karma&lt;/code&gt; webpack plugin from your &lt;code&gt;karma.conf.js&lt;/code&gt; (if you have one).&lt;/p&gt;
&lt;p&gt;Shifting to &lt;code&gt;builderMode: application&lt;/code&gt; is quite a bit faster.
On a project with thousands of tests, the full test suite was ~40% faster,
cutting nearly a minute from the total time.
In watch mode, the difference is also quite noticeable,
shaving a few seconds on each re-run.&lt;/p&gt;
&lt;h3&gt;Zoneless experiment&lt;/h3&gt;
&lt;p&gt;A new option &lt;code&gt;--experimental-zoneless&lt;/code&gt; has been added to the &lt;code&gt;ng new&lt;/code&gt; command,
generating a new project without Zone.js.
Unit tests are also generated with the proper providers to make them work without Zone.js.
You can check out our &lt;a href=&quot;/2024/05/22/what-is-new-angular-18.0/#zoneless-experiment&quot;&gt;blog post on Angular 18.0&lt;/a&gt; for more information on this experiment.&lt;/p&gt;
&lt;h3&gt;ng generate component&lt;/h3&gt;
&lt;p&gt;A new &lt;code&gt;--export-default&lt;/code&gt; option has been added to the &lt;code&gt;ng generate component&lt;/code&gt; command.
It changes the component to use the default export syntax: &lt;code&gt;export default class AdminComponent&lt;/code&gt;.
This can be interesting for lazy-loaded components, as the &lt;code&gt;loadComponent&lt;/code&gt; syntax then &lt;a href=&quot;/2022/11/16/what-is-new-angular-15.0/&quot;&gt;allows to write&lt;/a&gt; &lt;code&gt;loadComponent: () =&amp;gt; import(&amp;#39;./admin/admin.component&amp;#39;)&lt;/code&gt; instead of the usual &lt;code&gt;loadComponent: () =&amp;gt; import(&amp;#39;./admin/admin.component&amp;#39;).then(m =&amp;gt; m.AdminComponent)&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Sass deprecation warnings&lt;/h3&gt;
&lt;p&gt;It&amp;#39;s now possible to silence the deprecation warnings coming from the Sass compiler:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;stylePreprocessorOptions&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;sass&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;silenceDeprecations&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&amp;#39;s also possible to throw an error if a deprecation warning is emitted with &lt;code&gt;fatalDeprecations&lt;/code&gt;
and to prepare for future deprecations with &lt;code&gt;futureDeprecations&lt;/code&gt;.
This feature is going to be really useful to all Sass users,
as some APIs are getting deprecated and will be removed in Sass v3,
so you may see a bunch of deprecation warnings appear.&lt;/p&gt;
&lt;h3&gt;Strict CSP&lt;/h3&gt;
&lt;p&gt;A new option has been added to the &lt;code&gt;ng build&lt;/code&gt; command to enable a
strict Content Security Policy (CSP) in the generated &lt;code&gt;index.html&lt;/code&gt; file.
This option applies the recommendations from this &lt;a href=&quot;https://web.dev/articles/strict-csp#choose-hash&quot;&gt;Web.dev article&lt;/a&gt;
and enables automatic generation of a hash-based CSP based on scripts in the &lt;code&gt;index.html&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;To enable this option, set the &lt;code&gt;security.autoCsp&lt;/code&gt; configuration to &lt;code&gt;true&lt;/code&gt; in your &lt;code&gt;angular.json&lt;/code&gt; file.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;Wow, that was a lot of new features in Angular v19!&lt;/p&gt;
&lt;p&gt;v20 will probably continue to stabilize
the signals APIs introduced these past months.
We can also hope for more news about how the router and forms will integrate with signals.
Stay tuned!&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>What&apos;s new in Vue 3.5?</title>
    <link href="https://blog.ninja-squad.com/2024/09/05/what-is-new-vue-3.5"/>
    <updated>2024-09-05T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2024/09/05/what-is-new-vue-3.5</id>
    <content type="html">
      &lt;p&gt;Vue&amp;nbsp;3.5.0 is here!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;a href=&quot;https://github.com/vuejs/core/blob/main/CHANGELOG.md#350-2024-09-03&quot;&gt;
    &lt;img class=&quot;img-fluid&quot; style=&quot;max-width: 60%&quot; src=&quot;/assets/images/vue.webp&quot; alt=&quot;Vue logo&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;The last minor release was v3.4.0 in December.
Since then, we have seen quite a few patch releases,
and some interesting new features.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s see what we have in this release!&lt;/p&gt;
&lt;h2&gt;Props destructuration&lt;/h2&gt;
&lt;p&gt;Props destructuration was introduced as an experiment in Vue 3.3 (as part of the reactive transform experiment) and is now stable in Vue 3.5.&lt;/p&gt;
&lt;p&gt;So instead of:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; props &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; withDefaults&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;defineProps&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;?:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Hello&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;watchEffect&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(props&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can now write:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; name &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Hello&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; defineProps&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;?:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;watchEffect&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(name))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// ☝️ This gets compiled to the same code as the previous example&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// so we don&apos;t lose the reactivity of the props&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You no longer need the &lt;code&gt;propsDestructure: true&lt;/code&gt; flag in the compiler options to use this feature,
so you can remove it if you have it.
You can however disable this feature by setting &lt;code&gt;propsDestructure: false&lt;/code&gt; in the compiler options,
or even throw an error if you want to enforce the use of the previous syntax by setting &lt;code&gt;propsDestructure: &amp;#39;error&amp;#39;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Read more about this feature in the &lt;a href=&quot;https://github.com/vuejs/rfcs/discussions/502&quot;&gt;RFC&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;useTemplateRef&lt;/h2&gt;
&lt;p&gt;As you probably know, Vue lets you grab a reference to an element in a template, using the &lt;code&gt;ref=&amp;quot;key&amp;quot;&lt;/code&gt; syntax. The framework then populates a Ref named &lt;code&gt;key&lt;/code&gt; in the setup of the component.
For example, to initialize a chart, you usually write code looking that:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;canvas&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;chart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;canvas&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// 👇 special ref that Vue populates with the element in the template&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; chart &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;HTMLCanvasElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;onMounted&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; Chart&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(chart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;!,&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; /* chart options */&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This API felt a bit awkward, as nothing was pointing out that this ref was &amp;quot;special&amp;quot; at first glance. It also forced developers to pass this ref around to composables.
For example, if you wanted to build a &lt;code&gt;useChart&lt;/code&gt; composable, you had to write it like this:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; useChart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;chartRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; Ref&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;HTMLCanvasElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  onMounted&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; Chart&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;chartRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;!,&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; /* chart options */&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then call it in your component by passing it the ref:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; chart &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;HTMLCanvasElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;useChart&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(chart)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Vue v3.5 introduces a new composable called &lt;code&gt;useTemplateRef&lt;/code&gt; to grab a reference in the template:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// useTemplateRef expects the key of the element in the template&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; chartRef &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; useTemplateRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;HTMLCanvasElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;chart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;onMounted&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; Chart&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(chartRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;!,&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; /* chart options */&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The type of &lt;code&gt;chartRef&lt;/code&gt; is a read-only &lt;code&gt;ShallowRef&amp;lt;HTMLCanvasElement | null&amp;gt;&lt;/code&gt;.
In addition to a more explicit name and usage, the new function is usable directly inside a composable. This simplifies the pattern we saw above, as &lt;code&gt;useChart&lt;/code&gt; can simply be written:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; useChart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;chartKey&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; chartRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; useTemplateRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;HTMLCanvasElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  onMounted&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; Chart&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;chartRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;!,&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; /* chart options */&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then used in a component:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;useChart&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;chart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a nice improvement!&lt;/p&gt;
&lt;h2&gt;useId&lt;/h2&gt;
&lt;p&gt;A new composition function called &lt;code&gt;useId&lt;/code&gt; has been added to generate a unique ID.
This feature is probably already familiar to &lt;a href=&quot;https://react.dev/reference/react/useId&quot;&gt;React developers&lt;/a&gt; or Nuxt developers who use the &lt;code&gt;useId&lt;/code&gt; composable.&lt;/p&gt;
&lt;p&gt;This can be useful when you need to generate an ID for an HTML element,
for example when you use a label with an input, or for accessibility attributes:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As the component can be rendered many times, you need to ensure that the ID is unique.
This is where &lt;code&gt;useId&lt;/code&gt; comes in:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; id &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; useId&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;useId&lt;/code&gt; guarantees that the generated ID is unique within the application.
By default, Vue generates an ID with a prefix of &lt;code&gt;v-&lt;/code&gt; followed by a unique number
(that increments when new components are rendered).
The prefix can be customized by using &lt;code&gt;app.config.idPrefix&lt;/code&gt;.
&lt;code&gt;useId&lt;/code&gt; also guarantees that the ID is stable between server-side rendering and client-side rendering, to avoid mismatching errors.&lt;/p&gt;
&lt;h2&gt;Lazy hydration strategies&lt;/h2&gt;
&lt;p&gt;Asynchronous components, defined with &lt;code&gt;defineAsyncComponent&lt;/code&gt;,
can now control when they should be hydrated using a new &lt;code&gt;hydrate&lt;/code&gt; option.&lt;/p&gt;
&lt;p&gt;Vue provides four strategies for hydration in v3.5:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;hydrateOnIdle()&lt;/code&gt;: the component will be hydrated when the browser is idle (you can specify a timeout if needed, as &lt;code&gt;requestIdleCallback&lt;/code&gt;, which is used internally, allows).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hydrateOnVisible()&lt;/code&gt;: the component will be hydrated when it becomes visible in the viewport (implemented using an &lt;code&gt;IntersectionObserver&lt;/code&gt;). Additional options supported by the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API&quot;&gt;&lt;code&gt;IntersectionObserver&lt;/code&gt; API&lt;/a&gt; can be passed to the strategy, like  &lt;code&gt;rootMargin&lt;/code&gt; to define the margin around the viewport. So you can use &lt;code&gt;hydrateOnVisible({ rootMargin: &amp;#39;100px&amp;#39; })&lt;/code&gt; to hydrate the component when it is 100px away from the viewport.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hydrateOnInteraction(event)&lt;/code&gt;: the component will be hydrated when the user interacts with the component with a defined event, for example &lt;code&gt;hydrateOnInteraction(&amp;#39;click&amp;#39;)&lt;/code&gt;. You can also specify an array of events.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hydrateOnMediaQuery(query)&lt;/code&gt;: the component will be hydrated when the media query matches. For example, &lt;code&gt;hydrateOnMediaQuery(&amp;#39;(min-width: 600px)&amp;#39;)&lt;/code&gt; will hydrate the component when the viewport is at least 600px wide.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can also define a define custom strategy if you want to.&lt;/p&gt;
&lt;p&gt;Here is an example of how to use these strategies:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; defineAsyncComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; hydrateOnVisible&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;vue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; User &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; defineAsyncComponent&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  loader&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; import&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;./UserComponent.vue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt; hydrate&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; hydrateOnVisible&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;100px&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;data-allow-mismatch&lt;/h2&gt;
&lt;p&gt;Vue 3.5 now supports a new attribute called &lt;code&gt;data-allow-mismatch&lt;/code&gt;,
that can be added to any element to allow client/server mismatch warnings
to be silenced for that element.&lt;/p&gt;
&lt;p&gt;For example, if you have a component that renders the current date like this:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;{{ currentDate }}&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;you might get a warning if the server and the client render the date at different times:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[Vue warn]: Hydration text content mismatch on &amp;#x3C;div&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; - rendered on server: Jul 26, 2024&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; - expected on client: Jul 27, 2024&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can silence this warning by adding the &lt;code&gt;data-allow-mismatch&lt;/code&gt; attribute:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; data-allow-mismatch&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;{{ currentDate }}&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The value of the attribute can be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;text&lt;/code&gt; to silence the warning for text content&lt;/li&gt;
&lt;li&gt;&lt;code&gt;children&lt;/code&gt; to silence the warning for children content&lt;/li&gt;
&lt;li&gt;&lt;code&gt;class&lt;/code&gt; to silence the warning for class mismatch&lt;/li&gt;
&lt;li&gt;&lt;code&gt;style&lt;/code&gt; to silence the warning for style mismatch&lt;/li&gt;
&lt;li&gt;&lt;code&gt;attribute&lt;/code&gt; to silence the warning for attribute mismatch&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Better types&lt;/h2&gt;
&lt;p&gt;A few improvements have been made to help the tooling understand the Vue API better.
For example, components that use &lt;code&gt;expose&lt;/code&gt; will now have a more correct type.&lt;/p&gt;
&lt;p&gt;An effort has also been made for directives.
It is now possible to specify the allowed modifiers for a directive in the type definition:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// can be used as v-focus.seconds in the template&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; vFocus&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; Directive&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;  HTMLInputElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;  boolean&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;seconds&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; /* 👈 New! only &apos;seconds&apos; is allowed as modifier */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;el&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; binding&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; secondsModifier&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; binding&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;modifiers&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;seconds&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // autocompletion works here&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The built-in directives have also been improved to leverage this new feature.&lt;/p&gt;
&lt;p&gt;Another improvement concerns the &lt;code&gt;computed&lt;/code&gt; function:
you can now define a getter and a setter with different types (it was already working but TS was complaining):&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;UserModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Cédric&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; json &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; computed&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  get&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; JSON&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;stringify&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇 the setter receives a UserModel instead of a string&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  set&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;newUser&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; UserModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; newUser;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // typed as ComputedRef&amp;#x3C;string, UserModel&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(json&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // 👈 a string&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;JB&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; };&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // 👈 no error&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;app.onUnmount()&lt;/h2&gt;
&lt;p&gt;It is now possible to register a callback that will be called when the app is unmounted
(i.e when the &lt;code&gt;app.unmount()&lt;/code&gt; method is called)
This can be useful to clean up resources or to log something if you unmount your application,
but it is even more useful for plugin developers.&lt;/p&gt;
&lt;p&gt;Here is an example:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; myPlugin&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; Plugin&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; App&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  function&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; cleanupSomeSideEffect&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; /* ...*/&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // Register the cleanup function to be called when the app is unmounted&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  app&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;onUnmount&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;cleanupSomeSideEffect&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Watcher novelties&lt;/h2&gt;
&lt;h3&gt;deep watch&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;watch&lt;/code&gt; function had a &lt;code&gt;deep&lt;/code&gt; option since the beginning.
It allows watching deeply nested properties of a ref:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; obj &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; super&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; nested&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; prop&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;watch&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(obj&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // called when the ref or one of its nested properties changes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;nested prop changed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;},&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; deep&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You don&amp;#39;t need it for a &lt;code&gt;reactive&lt;/code&gt; object though,
as &lt;code&gt;watch&lt;/code&gt; will automatically watch deeply nested properties of a reactive object.
In that case, &lt;code&gt;deep&lt;/code&gt; can be set to &lt;code&gt;false&lt;/code&gt; if you want to disable this behavior.&lt;/p&gt;
&lt;p&gt;The novelty introduced in Vue 3.5 is that you can now use &lt;code&gt;deep&lt;/code&gt; with a specific depth:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; obj &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; super&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; nested&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; prop&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;watch&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(obj&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // called when the ref or the first level of its nested properties changes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;nested prop changed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;},&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; deep&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // 👈 deep can now be a number&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;pause/resume&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;watch&lt;/code&gt; and &lt;code&gt;watchEffect&lt;/code&gt; can now be paused and resumed, in addition to being stopped.&lt;/p&gt;
&lt;p&gt;Until now, you could only stop a watcher, which would prevent it from being called again:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; stop &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; watch&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(obj&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;obj changed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;stop&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // 👈 stop the watcher&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, you can pause and resume a watcher:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; pause&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; resume&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; stop &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; watch&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(obj&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;obj changed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;pause&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // 👈 pause the watcher&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;resume&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // 👈 resume the watcher&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;stop&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // 👈 stop the watcher&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;onWatcherCleanup&lt;/h3&gt;
&lt;p&gt;A new API called &lt;code&gt;onWatcherCleanup&lt;/code&gt; has been added to register a callback that will be called when a &lt;code&gt;watch&lt;/code&gt;/&lt;code&gt;watchEffect&lt;/code&gt; is cleaned up.
This is similar to what the &lt;code&gt;onCleanup&lt;/code&gt; parameter of watchers does,
but it allows to use the cleanup function in functions called inside a watcher.&lt;/p&gt;
&lt;p&gt;Before&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// starts an interval, called in the watchEffect below&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; startInterval&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;intervalTime&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; onCleanup&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; window&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;setInterval&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;hello&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; intervalTime&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // we use onCleanup here to clear the interval&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  onCleanup&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; window&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;clearInterval&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; intervalTime &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;watchEffect&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;onCleanup&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Interval time changed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; intervalTime&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // we need to pass onCleanup to startInterval&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  startInterval&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;intervalTime&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; onCleanup&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; startInterval&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;intervalTime&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; window&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;setInterval&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;hello&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; intervalTime&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  //👇 we can now use onWatcherCleanup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  onWatcherCleanup&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; window&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;clearInterval&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; intervalTime &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;watchEffect&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Interval time changed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; intervalTime&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  //👇 no need to pass onCleanup anymore&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  startInterval&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;intervalTime&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;onWatcherCleanup&lt;/code&gt; throws a warning if there is no current active effect.
This warning can be silenced by passing a second parameter to &lt;code&gt;onWatcherCleanup&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;onWatcherCleanup&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // cleanup code&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;},&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; /* 👈 no warning */&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A similar API has been introduced for the low level &lt;code&gt;effect&lt;/code&gt; function, called &lt;code&gt;onEffectCleanup&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Trusted types&lt;/h2&gt;
&lt;p&gt;Vue 3.5 now supports &lt;a href=&quot;https://web.dev/trusted-types/&quot;&gt;Trusted Types&lt;/a&gt;.
It should work out of the box by default.
This is done by automatically converting the strings generated by the compiler into &lt;code&gt;TrustedHTML&lt;/code&gt; when they are used in a context where a Trusted Type is expected.
&lt;code&gt;v-html&lt;/code&gt; is not supported out-of-the-box, but can also be used if you declare a custom policy.&lt;/p&gt;
&lt;h2&gt;throwUnhandledErrorInProduction&lt;/h2&gt;
&lt;p&gt;A new option has been added to the app configuration to throw unhandled errors in production.
This can be useful to catch errors that are currently not caught because the default behavior is to log them in the console.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; app &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; createApp&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(App)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;throwUnhandledErrorInProduction &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this option enabled, you&amp;#39;ll easily catch errors when rendering your application in production.
Note that the default is &lt;code&gt;false&lt;/code&gt; to avoid breaking existing applications.&lt;/p&gt;
&lt;h2&gt;Teleport&lt;/h2&gt;
&lt;h3&gt;deferred Teleport&lt;/h3&gt;
&lt;p&gt;It is now possible to add a &lt;code&gt;defer&lt;/code&gt; attribute to &lt;code&gt;Teleport&lt;/code&gt; to mark the component as deferred.
When doing so, the target of the teleportation doesn&amp;#39;t have to already exist:
even if it appears later, the target can still be resolved.
A deferred Teleport waits until all other DOM content in the same update cycle has been rendered before locating the target container.&lt;/p&gt;
&lt;p&gt;So we can now use &lt;code&gt;Teleport&lt;/code&gt; with targets located in other components (as long as they are mounted in the same tick), or even use &lt;code&gt;Teleport&lt;/code&gt; and a target inside a &lt;code&gt;Suspense&lt;/code&gt; (whereas you previously had to target a container outside of the &lt;code&gt;Suspense&lt;/code&gt; component).&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;Suspense&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;Teleport&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; defer&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;#target&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;Teleport&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;Suspense&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Teleport and Transition&lt;/h3&gt;
&lt;p&gt;It is now possible to use a &lt;code&gt;Teleport&lt;/code&gt; component directly inside a &lt;code&gt;Transition&lt;/code&gt; component,
thus allowing to animate the appearance and the disappearance of an element in a different place in the DOM. This used to throw an error in Vue 3.4.&lt;/p&gt;
&lt;p&gt;You can check out this &lt;a href=&quot;https://play.vuejs.org/&quot;&gt;playground&lt;/a&gt; from the PR author &lt;a href=&quot;https://github.com/edison1105&quot;&gt;edison1105&lt;/a&gt;, showcasing this new feature.&lt;/p&gt;
&lt;h2&gt;Custom elements&lt;/h2&gt;
&lt;p&gt;Vue v3.5 adds a bunch of features for custom elements.
As I don&amp;#39;t personally use them, I&amp;#39;ll just list the most notable here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;defineCustomElement&lt;/code&gt; now supports disabling ShadowDom by setting the &lt;code&gt;shadowRoot&lt;/code&gt; option to &lt;code&gt;false&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;useHost()&lt;/code&gt; composable has been added to get the host element and a &lt;code&gt;useShadowRoot()&lt;/code&gt; composable has been added to get the shadow root of the custom element (which can be useful for CSS in JS);&lt;/li&gt;
&lt;li&gt;&lt;code&gt;emit&lt;/code&gt; now supports specifying event options, like &lt;code&gt;emit(&amp;#39;event&amp;#39;, { bubbles: true })&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;expose&lt;/code&gt; is now available in custom elements;&lt;/li&gt;
&lt;li&gt;custom elements can now define a &lt;code&gt;configureApp&lt;/code&gt; method to configure the associated app instance,
for example to use plugins like the router;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Developer experience&lt;/h2&gt;
&lt;p&gt;The Vue compiler will now emit a warning if you write invalid HTML nesting in your template (for example, a &lt;code&gt;div&lt;/code&gt; inside a &lt;code&gt;p&lt;/code&gt;):&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;warning: &amp;#x3C;div&gt; cannot be child of &amp;#x3C;p&gt;, according to HTML specifications. This can cause hydration errors or potentially disrupt future functionality.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We also have a new warning when a &lt;code&gt;computed&lt;/code&gt; is self-triggering (i.e. it writes to one of its dependencies in its getter):&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Computed is still dirty after getter evaluation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;likely because a computed is mutating its own dependency in its getter.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;State mutations in computed getters should be avoided.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Check the docs for more details: https://vuejs.org/guide/essentials/computed.html#getters-should-be-side-effect-free&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This warning is not enabled by default, you need to set &lt;code&gt;app.config.warnRecursiveComputed&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt; in your application configuration.&lt;/p&gt;
&lt;h2&gt;Performances&lt;/h2&gt;
&lt;p&gt;A whole lot of optimizations have been made around reactivity.
The first notable one is that the reactivity system now uses a new algorithm to track dependencies.
It now relies on version counting and doubly linked lists.
If I&amp;#39;m not mistaken, this is really similar to what Preact did and explained in &lt;a href=&quot;https://preactjs.com/blog/signal-boosting/&quot;&gt;this really interesting article&lt;/a&gt;.
This brings a few performance improvements (most notably around memory usage) and should make the reactivity system more predictable (computed values should now never be stale).&lt;/p&gt;
&lt;p&gt;The other notable change is that array manipulation should also be faster, especially for large arrays.&lt;/p&gt;
&lt;h2&gt;News from the ecosystem&lt;/h2&gt;
&lt;h3&gt;Vapor mode&lt;/h3&gt;
&lt;p&gt;Vapor (&lt;code&gt;@vue/vapor&lt;/code&gt;) is making progress within its &lt;a href=&quot;https://github.com/vuejs/core-vapor&quot;&gt;repository&lt;/a&gt;. You can play with it using the online REPL &lt;a href=&quot;https://vapor-repl.netlify.app&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Vue router&lt;/h3&gt;
&lt;p&gt;Vue Router 4.4.0 is out and offers the possibility to have typed routes!&lt;/p&gt;
&lt;p&gt;This can be done manually by adding the types yourself to your project
(for example in &lt;code&gt;env.d.ts&lt;/code&gt;):&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; RouteNamedMap&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // a route with no params, named &apos;users&apos; and matching &apos;/users&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt; users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; RouteRecordInfo&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;/users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; Record&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;never&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; never&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // a route with a param named &apos;id&apos;, named &apos;user&apos; and matching &apos;/user/:id&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; RouteRecordInfo&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;/users/:id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; },&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // raw parameters (allows to use the route with a number or a string)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // parameters we get with useRoute&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;declare&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; module&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;vue-router&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  interface&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; TypesConfig&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt; RouteNamedMap&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; RouteNamedMap&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then when you use a &lt;code&gt;RouterLink&lt;/code&gt; or &lt;code&gt;router.push&lt;/code&gt;, you get a nice auto-completion
and type-checking:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;&amp;#x3C;!-- 👇 you get an error if the route name has a typo --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;&amp;#x3C;!-- or if you define a parameter that does not exist or forget to define it --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;RouterLink&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;to&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; params&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;id &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;RouterLink&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then when using &lt;code&gt;useRoute&lt;/code&gt;, you get a typed &lt;code&gt;route&lt;/code&gt; object:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// note the name of the route as a parameter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// which is necessary for TypeScript to know the type of the route&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; route &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; useRoute&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(route&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;id)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // 👈 id is properly typed as a string!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(route&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;other)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // 👈 this throws an error&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a nice addition even if manually defining the types is a bit cumbersome.&lt;/p&gt;
&lt;p&gt;Note that if you are into file-based routing,
you can use &lt;a href=&quot;https://uvr.esm.is/&quot;&gt;unplugin-vue-router&lt;/a&gt; which will automatically generate the types for you! The plugin is still experimental though.&lt;/p&gt;
&lt;h3&gt;create-vue&lt;/h3&gt;
&lt;p&gt;A new option has been added to &lt;code&gt;create-vue&lt;/code&gt; to allow you to use the new &lt;a href=&quot;https://devtools-next.vuejs.org/&quot;&gt;Devtools plugin&lt;/a&gt;,
a Vite plugin that allows you to use the Vue Devtools directly in the browser with an overlay.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; create&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; vue@latest&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; my-app&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; --devtools&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Nuxt&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://nuxt.com/blog/v3-12&quot;&gt;Nuxt v3.12&lt;/a&gt; is out and paves the way for Nuxt 4.
You can try the changes using:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; defineNuxtConfig&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt; future&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;   compatibilityVersion&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;#39;s all for this release. Stay tuned for the next one!&lt;/p&gt;
&lt;p&gt;Our &lt;a href=&quot;https://books.ninja-squad.com/vue&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://vue-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/vue&quot;&gt;training&lt;/a&gt; are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>What&apos;s new in Angular 18.2?</title>
    <link href="https://blog.ninja-squad.com/2024/08/14/what-is-new-angular-18.2"/>
    <updated>2024-08-14T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2024/08/14/what-is-new-angular-18.2</id>
    <content type="html">
      &lt;p&gt;Angular&amp;nbsp;18.2.0 is here!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;a href=&quot;https://github.com/angular/angular/releases/tag/18.2.0&quot;&gt;
    &lt;img class=&quot;img-fluid&quot; style=&quot;max-width: 60%&quot; src=&quot;/assets/images/angular_gradient.webp&quot; alt=&quot;Angular logo&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;This is a minor release with some nice features: let&amp;#39;s dive in!&lt;/p&gt;
&lt;h2&gt;Automatic flush in fakeAsync&lt;/h2&gt;
&lt;p&gt;In Angular v18.2 (and zone.js v0.15), the &lt;code&gt;flush()&lt;/code&gt; function is now automatically called at the end of a &lt;code&gt;fakeAsync()&lt;/code&gt; test.&lt;/p&gt;
&lt;p&gt;Before this version, you had to call &lt;code&gt;flush()&lt;/code&gt; yourself at the end of your test to flush all pending asynchronous tasks or &lt;code&gt;discardPeriodicTasks()&lt;/code&gt; for periodic tasks. If you didn&amp;#39;t do it, you would get the error &lt;code&gt;1 periodic timer(s) still in the queue&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The way to fix it was to call &lt;code&gt;flush()&lt;/code&gt; or &lt;code&gt;discardPeriodicTasks()&lt;/code&gt; at the end of your test:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;it&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;should do something&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; fakeAsync&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  flush&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is no longer necessary, as Angular will do it for you
(if you manually set the &lt;code&gt;flush&lt;/code&gt; option to true with Angular v18.2/zone.js v0.14,
and will be done by default by Angular in v19/zone.js v0.15).&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;it&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;should do something&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; fakeAsync&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // no flush() or discardPeriodicTasks() required!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;},&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; flush&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When zone.js v0.15 is released, you won&amp;#39;t need to specify the &lt;code&gt;flush&lt;/code&gt; option anymore, as it will be done automatically for you:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;it&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;should do something&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; fakeAsync&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  flush&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;whenStable helper&lt;/h2&gt;
&lt;p&gt;A new helper method has been added to &lt;code&gt;ApplicationRef&lt;/code&gt; to wait for the application to become stable. &lt;code&gt;whenStable&lt;/code&gt; is really similar to the existing &lt;code&gt;isStable&lt;/code&gt; method, but it returns a promise that resolves when the application is stable instead of an observable.&lt;/p&gt;
&lt;h2&gt;defaultQueryParamsHandling in router&lt;/h2&gt;
&lt;p&gt;It is now possible to specify the default query params handling strategy for all routes in the &lt;code&gt;provideRouter()&lt;/code&gt; configuration.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;provideRouter&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(routes&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; withRouterConfig&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; defaultQueryParamsHandling&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;merge&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By default, Angular uses the &lt;code&gt;replace&lt;/code&gt; strategy, but you can also use &lt;code&gt;preserve&lt;/code&gt; or &lt;code&gt;merge&lt;/code&gt;.
Previously, you could only specify this strategy on a per-navigation basis (via &lt;code&gt;RouterLink&lt;/code&gt; or &lt;code&gt;router.navigate&lt;/code&gt; options).&lt;/p&gt;
&lt;h2&gt;Migrations&lt;/h2&gt;
&lt;p&gt;An optional migration has been added to migrate dependency injection done via the constructor to the &lt;code&gt;inject&lt;/code&gt; function.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ng&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; g&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; @angular/core:inject&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will update your code from:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; UserComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  constructor&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; userService&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; UserService&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; UserComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  private&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; userService&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; inject&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(UserService)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that you might have some compilation errors after this migration,
most notably if you were using &lt;code&gt;new UserComponent(userService)&lt;/code&gt; in your tests.
There are a few options for this migration, and one can mitigate this issue:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;path&lt;/code&gt;, the directory to run the migration. By default: &lt;code&gt;.&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;migrateAbstractClasses&lt;/code&gt;, whether to migrate the abstract classes or not (which may break your code and necessitate to manually fixing it). By default: &lt;code&gt;false&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;backwardsCompatibleConstructors&lt;/code&gt;: by default, constructors that are empty after the migration are deleted. This can lead to compilation errors like the one I&amp;#39;m mentioning above. To prevent that, you can generate backward-compatible constructors with this option 
(which looks like: &lt;code&gt;constructor(...args: unknown[]);&lt;/code&gt;). By default: &lt;code&gt;false&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nonNullableOptional&lt;/code&gt;: whether to cast the optional inject sites to be non-nullable or not. By default: &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The migration is &lt;em&gt;optional&lt;/em&gt; and the Angular team explicitly said that the constructor injection will still be supported in the future.
However, it does indicate that the future of Angular might be to use the &lt;code&gt;inject&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;Another optional migration has been added to convert standalone components used in routes
to be lazy-loaded if that&amp;#39;s not the case:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ng&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; g&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; @angular/core:route-lazy-loading&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will update your code from:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;  path&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;  component&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; UsersComponent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;  path&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;  loadComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; import&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;./users/users.component&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;then&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;m&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; m&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;UsersComponent&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The only option for this migration is the &lt;code&gt;path&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Diagnostics&lt;/h2&gt;
&lt;p&gt;A new diagnostic has been added to catch uncalled functions in event bindings: &lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; (click)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Log in&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;throws: &lt;code&gt;NG8111: Function in event binding should be invoked: login()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Another one was added to catch unused &lt;code&gt;@let&lt;/code&gt; declaration (a new feature introduced in &lt;a href=&quot;/2024/07/10/what-is-new-angular-18.1&quot;&gt;Angular 18.1&lt;/a&gt;): &lt;code&gt;NG8112: @let user is declared but its value is never read.&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Angular CLI&lt;/h2&gt;
&lt;p&gt;The application builder now supports attribute-based loader configuration&lt;/p&gt;
&lt;p&gt;For example, an SVG file can be imported as text via:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// @ts-expect-error TypeScript cannot provide types based on attributes yet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import contents from &apos;./some-file.svg&apos; with { loader: &apos;text&apos; };&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This overrides all other configurations (for example a &lt;code&gt;loader&lt;/code&gt; defined in &lt;code&gt;angular.json&lt;/code&gt;).&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;That&amp;#39;s all for this release, stay tuned!&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>What&apos;s new in Angular 18.1?</title>
    <link href="https://blog.ninja-squad.com/2024/07/10/what-is-new-angular-18.1"/>
    <updated>2024-07-10T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2024/07/10/what-is-new-angular-18.1</id>
    <content type="html">
      &lt;p&gt;Angular&amp;nbsp;18.1.0 is here!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;a href=&quot;https://github.com/angular/angular/releases/tag/18.1.0&quot;&gt;
    &lt;img class=&quot;img-fluid&quot; style=&quot;max-width: 60%&quot; src=&quot;/assets/images/angular_gradient.webp&quot; alt=&quot;Angular logo&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;This is a minor release with some nice features: let&amp;#39;s dive in!&lt;/p&gt;
&lt;h2&gt;TypeScript 5.5 support&lt;/h2&gt;
&lt;p&gt;Angular v18.1 now supports TypeScript 5.5. This means that you can use the latest version of TypeScript in your Angular applications. You can check out the &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-5/&quot;&gt;TypeScript 5.5 release notes&lt;/a&gt; to learn more about the new features: it&amp;#39;s packed with new things! For example, it&amp;#39;s no longer necessary to manually define type guards when filtering arrays, with the new &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-5/#inferred-type-predicates&quot;&gt;inferred type predicate feature&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;@let syntax&lt;/h2&gt;
&lt;p&gt;The main feature of this release is undoubtedly the new &lt;code&gt;@let&lt;/code&gt; syntax in Angular templates.
This new syntax (in developer preview) allows you to define a template variable in the template itself,
without having to declare it in the component class.&lt;/p&gt;
&lt;p&gt;The syntax is &lt;code&gt;@let name = expression;&lt;/code&gt;, where &lt;code&gt;name&lt;/code&gt; is the name of the variable (and can be any valid JavaScript variable name) and &lt;code&gt;expression&lt;/code&gt; is the value of the variable.
Let’s say our component has a count field defined in its class, then we can define a variable in the template like this:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;@let&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; countPlustwo &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;count &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; countPlustwo &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the &lt;code&gt;count&lt;/code&gt; value changes, then the &lt;code&gt;countPlustwo&lt;/code&gt; value will be updated automatically.
This also works with the &lt;code&gt;async&lt;/code&gt; pipe (and the other ones, of course):&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;@let&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;user$ &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (user) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that you can&amp;#39;t declare several variables (with &lt;code&gt;@let&lt;/code&gt; or &lt;code&gt;#&lt;/code&gt;) with the same name in the same template:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;NG8017: Cannot declare @let called &apos;value&apos; as there is another symbol in the template with the same name.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You also can&amp;#39;t use a variable before its declaration:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;NG8016: Cannot read @let declaration &apos;user&apos; before it has been defined.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which prevents to use it like &lt;code&gt;@let user = user()&lt;/code&gt; in case you thought about unwrapping a signal value into a variable of the same name.&lt;/p&gt;
&lt;p&gt;This new feature can be handy when you want to use a value in several places in your template, especially if it is a complex expression. Sometimes you can create a dedicated field in the component class, but sometimes you can’t, for example in a for loop:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@for&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(user &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; track&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;id) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;lastName &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;firstName &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;address&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;shippingAddress&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;number &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;&amp;#x26;nbsp;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;shippingAddress&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;street &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;&amp;#x26;nbsp;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;shippingAddress&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;zipcode &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;&amp;#x26;nbsp;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;shippingAddress&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;city &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can be written more cleanly using &lt;code&gt;@let&lt;/code&gt; 🚀:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@for&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(user &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; track&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;id) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;lastName &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;firstName &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;address&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;    @let&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; address &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;shippingAddress&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; address&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;number &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;&amp;#x26;nbsp;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; address&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;street &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;&amp;#x26;nbsp;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; address&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;zipcode &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;&amp;#x26;nbsp;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; address&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;city &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;afterRender/afterNextRender APIs&lt;/h2&gt;
&lt;p&gt;Angular v16.2 introduced two new APIs to run code after the rendering of a component: &lt;code&gt;afterRender&lt;/code&gt; and &lt;code&gt;afterNextRender&lt;/code&gt;.
You can read more about them in our &lt;a href=&quot;/2023/08/09/what-is-new-angular-16.2/&quot;&gt;Angular 16.2 blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In Angular v18.1, these APIs have been changed (they are still marked as experimental) to no longer need a &lt;code&gt;phase&lt;/code&gt; parameter, which was introduced in Angular v17, as we explained
in our &lt;a href=&quot;/2023/11/09/what-is-new-angular-17.0/&quot;&gt;Angular 17 blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;phase&lt;/code&gt; parameter is now deprecated: we now pass to these functions an object instead of a callback, to specify the phases you want to use.
You can still use the callback form with no phase,
which is equivalent to using the &lt;code&gt;MixedReadWrite&lt;/code&gt; mode.
There are 4 phases available in the new object form:
&lt;code&gt;earlyRead&lt;/code&gt;, &lt;code&gt;mixedReadWrite&lt;/code&gt;, &lt;code&gt;read&lt;/code&gt;, and &lt;code&gt;write&lt;/code&gt;.
If you only need to read something, you can use the &lt;code&gt;read&lt;/code&gt; phase.
If you need to write something that affects the layout, you need to use &lt;code&gt;write&lt;/code&gt;.
For example, to initialize a chart in your template:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ChartComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  @&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;ViewChild&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;canvas&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;canvas&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;!:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ElementRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;HTMLCanvasElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  constructor&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    afterNextRender&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;      write&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; ctx&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;canvas&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;nativeElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;        new&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; Chart&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;ctx&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;line&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; data&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If your &lt;code&gt;write&lt;/code&gt; callback depends on something you need to read first,
you must use &lt;code&gt;earlyRead&lt;/code&gt; to get the information you need before the &lt;code&gt;write&lt;/code&gt; phase,
and Angular will call the &lt;code&gt;write&lt;/code&gt; callback with the value returned by the &lt;code&gt;earlyRead&lt;/code&gt; callback:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;afterRender&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  earlyRead&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; nativeEl&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;getBoundingClientRect&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  //👇 The `rect` parameter is the value returned by the `earlyRead` callback&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  write&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;rect&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;    otherNativeEl&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;width&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; rect&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;width&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This exists to avoid intermixing reads and writes if possible,
and thus make things faster by avoiding &amp;quot;layout trashing&amp;quot;.
We previously had to call &lt;code&gt;afterRender&lt;/code&gt; twice, once for the read and once for the write phase,
but now we can do it in a single call, which is more efficient and cleaner.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;phase&lt;/code&gt; option still exists but is now deprecated.
Even if these APIs are an experimental feature, the Angular team provided a migration schematics to update your code to the new syntax 😍.&lt;/p&gt;
&lt;h2&gt;toSignal equality function&lt;/h2&gt;
&lt;p&gt;As you may know, if you read &lt;a href=&quot;/2023/04/26/angular-signals/&quot;&gt;our blog post about signals&lt;/a&gt;,
a &lt;code&gt;Signal&lt;/code&gt; can define its own equality function (it uses &lt;code&gt;Object.is&lt;/code&gt; by default).&lt;/p&gt;
&lt;p&gt;In Angular v18.1, the &lt;code&gt;toSignal&lt;/code&gt; function now also accepts an &lt;code&gt;equal&lt;/code&gt; parameter to specify the equality function to use in the signal it creates.&lt;/p&gt;
&lt;h2&gt;RouterLink with UrlTree&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;RouterLink&lt;/code&gt; directive now accepts an &lt;code&gt;UrlTree&lt;/code&gt; as input. This allows you to pass a pre-constructed &lt;code&gt;UrlTree&lt;/code&gt; to the &lt;code&gt;RouterLink&lt;/code&gt; directive, which can be useful in some cases.&lt;/p&gt;
&lt;p&gt;Until now, we could pass either a string or an array to the &lt;code&gt;RouterLink&lt;/code&gt; directive. For example, we could write:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [routerLink]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;[&apos;/users&apos;, user.id]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;User &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can also use an &lt;code&gt;UrlTree&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; HomeComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  userPath&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; inject&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(Router)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;createUrlTree&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;/users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;id])&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and in the template:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [routerLink]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;userPath&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;User &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that when doing so, you can&amp;#39;t define the &lt;code&gt;queryParams&lt;/code&gt;, &lt;code&gt;fragment&lt;/code&gt;, &lt;code&gt;queryParamsHandling&lt;/code&gt;
and &lt;code&gt;relativeTo&lt;/code&gt; inputs of the &lt;code&gt;RouterLink&lt;/code&gt; directive in the template.
You have to define them in the &lt;code&gt;UrlTree&lt;/code&gt; itself, or you&amp;#39;ll see the following error:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Error: NG04016: Cannot configure queryParams or fragment when using a UrlTree as the routerLink input value.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Router browserUrl&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;NavigationBehaviorOptions&lt;/code&gt; object,
used for the options of the &lt;code&gt;navigate&lt;/code&gt;/&lt;code&gt;navigateByUrl&lt;/code&gt; of the &lt;code&gt;Router&lt;/code&gt; service
or the &lt;code&gt;RedirectCommand&lt;/code&gt; object introduced in &lt;a href=&quot;/2024/05/22/what-is-new-angular-18.0/&quot;&gt;Angular v18&lt;/a&gt;
now accepts a &lt;code&gt;browserUrl&lt;/code&gt; option.
This option allows you to specify the URL that will be displayed in the browser&amp;#39;s address bar when the navigation is done, even if the matched URL is different.
This does not affect the internal router state (the &lt;code&gt;url&lt;/code&gt; of the &lt;code&gt;Router&lt;/code&gt; will still be the matched one) but only the browser&amp;#39;s address bar.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; canActivate&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; CanActivateFn&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; userService&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; inject&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;UserService&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; router&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; inject&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Router&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;userService&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;isLoggedIn&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; targetOfCurrentNavigation&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; router&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;getCurrentNavigation&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;?.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;finalUrl&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; redirect&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; router&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;parseUrl&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;/401&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // Redirect to /401 internally but display the original URL in the browser&apos;s address bar&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; RedirectCommand&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;redirect&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      browserUrl&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; targetOfCurrentNavigation&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Extended diagnostic for uncalled functions&lt;/h2&gt;
&lt;p&gt;A new extended diagnostic has been added to warn about uncalled functions in event bindings:&lt;/p&gt;
&lt;p&gt;So for example:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; (click)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;addUser&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Add user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;yields the following error (if you have &lt;code&gt;strictTemplates&lt;/code&gt; enabled):&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;NG8111: Functions must be invoked in event bindings: addUser()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Angular CLI&lt;/h2&gt;
&lt;h3&gt;faster builds with isolatedModules&lt;/h3&gt;
&lt;p&gt;TypeScript has an &lt;a href=&quot;https://www.typescriptlang.org/tsconfig/#isolatedModules&quot;&gt;option called &lt;code&gt;isolatedModules&lt;/code&gt;&lt;/a&gt;
that warns you if you write code that can&amp;#39;t be understood by other tools
by just looking at a single file.&lt;/p&gt;
&lt;p&gt;If you enable this option on your project, you should hopefully have no warnings,
and you can get a nice boost in build performances, as CLI v18.1 will delegate the transpilation of your TS files into JS files to esbuild instead of the TypeScript compiler 🚀&lt;/p&gt;
&lt;p&gt;On a rather large application, &lt;code&gt;ng build&lt;/code&gt; went from 49s to 32s, just by adding &lt;code&gt;isolatedModules: true&lt;/code&gt; in my &lt;code&gt;tsconfig.json&lt;/code&gt; file 🤯.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;isolatedModules&lt;/code&gt; will be enabled by default in the new projects generated by the CLI.&lt;/p&gt;
&lt;h3&gt;WASM support&lt;/h3&gt;
&lt;p&gt;The CLI now supports the usage of Web Assembly... in zoneless applications!
The application can&amp;#39;t use ZoneJS as the CLI needs to use native async/await to load WASM code
and ZoneJS prevents that.&lt;/p&gt;
&lt;p&gt;Anyway this can be interesting for some people, and you can write code like:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; hash&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;./hash.wasm&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;hash&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(myFile))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;inspect option&lt;/h3&gt;
&lt;p&gt;We can note the addition of a &lt;code&gt;--inspect&lt;/code&gt; option for &lt;code&gt;ng serve&lt;/code&gt;/&lt;code&gt;ng dev&lt;/code&gt;, only possible for SSR/SSG applications.
This flag starts a debug process, by default on port 9229,
allowing to attach a debugger to go through the code executed on the server.
You can use Chrome Inspect, VS Code, or your favorite IDE to attach to the process
(see the &lt;a href=&quot;https://nodejs.org/en/learn/getting-started/debugging&quot;&gt;NodeJS docs&lt;/a&gt;).
You can then add breakpoints into your code,
and the debugger will stop when this code is executed on the server when you load the corresponding page in your browser.
You can specify a different host or port if needed with &lt;code&gt;ng serve --inspect localhost:9999&lt;/code&gt; for example.&lt;/p&gt;
&lt;h3&gt;chunk optimizer&lt;/h3&gt;
&lt;p&gt;If you want to reduce the number of chunk files,
an experimental optimization has been added to the build step.
You may have noticed that since we shifted from webpack to esbuild as the underlying build tool,
the number of generated chunks has increased quite a bit.
This is because there is no real optimization done on chunks.
So we sometimes end up with really small chunks when running &lt;code&gt;ng build&lt;/code&gt;.
Some build tools have options to specify a minimal size, but esbuild doesn&amp;#39;t.
That&amp;#39;s why the CLI team is experimenting with an additional rollup pass
to optimize the generated chunks and try to merge some of them
or add some directly into the main bundle when it makes sense.&lt;/p&gt;
&lt;p&gt;On one of our largest applications, it reduces by half the number of chunks,
and the initial page now only needs to load 3 JS files instead of... 118 😲.
It does add a bit of build time though.&lt;/p&gt;
&lt;p&gt;To try this on your own application, you can run:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;NG_BUILD_OPTIMIZE_CHUNKS=1 ng build&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is still experimental for now but will probably be enabled automatically in a future version,
based on the initial file entry count and size.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;That&amp;#39;s all for this release, stay tuned!&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>What&apos;s new in Angular 18.0?</title>
    <link href="https://blog.ninja-squad.com/2024/05/22/what-is-new-angular-18.0"/>
    <updated>2024-05-22T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2024/05/22/what-is-new-angular-18.0</id>
    <content type="html">
      &lt;p&gt;Angular&amp;nbsp;18.0.0 is here!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;a href=&quot;https://github.com/angular/angular/releases/tag/18.0.0&quot;&gt;
    &lt;img class=&quot;img-fluid&quot; style=&quot;max-width: 60%&quot; src=&quot;/assets/images/angular_gradient.webp&quot; alt=&quot;Angular logo&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;This is a major release with some nice features: let&amp;#39;s dive in!&lt;/p&gt;
&lt;h2&gt;Control flow syntax is now stable!&lt;/h2&gt;
&lt;p&gt;The control flow syntax introduced in Angular 17 is no longer a developer preview feature and can safely be used.
As it is now the recommended way to write templates, you should consider using it in your applications.
You can easily migrate your applications using the provided schematics.&lt;/p&gt;
&lt;p&gt;👉 To learn more, check out our dedicated &lt;a href=&quot;/2023/10/11/angular-control-flow-syntax&quot;&gt;blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since we wrote this blog post, two warnings have been added to catch potential issues in your templates with for loops.&lt;/p&gt;
&lt;p&gt;As you know the &lt;code&gt;track&lt;/code&gt; option is now mandatory in &lt;code&gt;@for&lt;/code&gt; loops.
A new warning has been added in development mode to warn you if you have duplicated keys used by the &lt;code&gt;track&lt;/code&gt; option:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;WARN:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;NG0955: The provided track expression resulted in duplicated keys for a given collection.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Adjust the tracking expression such that it uniquely identifies all the items in the collection.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Duplicated keys were:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;key &quot;duplicated-key&quot; at index &quot;0&quot; and &quot;1&quot;.&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a warning that you can see in the browser console or when running unit tests.
It typically happens if you pick a property that is not unique in your collection.&lt;/p&gt;
&lt;p&gt;Another warning has been added to catch potential issues with the tracking expression.
If the tracking expression leads to the destruction and recreation of the complete collection, a warning will be displayed:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;WARN:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;NG0956: The configured tracking expression (track by identity)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;caused re-creation of the entire collection of size 20.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;This is an expensive operation requiring destruction and subsequent creation of DOM nodes, directives, components etc.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Please review the &quot;track expression&quot; and make sure that it uniquely identifies items in a collection.&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This typically happens if you use the &lt;code&gt;track item&lt;/code&gt; option and if you recreate all the collection items when there is a change.
Note that the warning only applies if the repeated element is considered &amp;quot;expensive&amp;quot; to create, but the bar is currently set quite low (a text node with a binding is already considered expensive).&lt;/p&gt;
&lt;h2&gt;Defer syntax is stable&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;@defer&lt;/code&gt; syntax is also stable.
&lt;code&gt;@defer&lt;/code&gt; lets you define a block of template that will be loaded lazily when a condition is met
(with all the components, pipes, directives, and libraries used in this block lazily loaded as well).&lt;/p&gt;
&lt;p&gt;👉 We wrote a detailed &lt;a href=&quot;/2023/11/02/angular-defer&quot;&gt;blog post about this feature&lt;/a&gt; if you want to learn more about it.&lt;/p&gt;
&lt;h2&gt;Signal standardization proposal&lt;/h2&gt;
&lt;p&gt;This is not an Angular v18 news, but as you may have heard, some of the most popular framework authors
(included the Angular and Vue team for example) have been working on a proposal to standardize signals in the JavaScript language.&lt;/p&gt;
&lt;p&gt;The proposal is at the first stage, so it might take a long time,
probably at least several years, or even never happened.&lt;/p&gt;
&lt;p&gt;You can deep dive into &lt;a href=&quot;https://github.com/tc39/proposal-signals&quot;&gt;the proposal&lt;/a&gt; or into this interesting &lt;a href=&quot;https://eisenbergeffect.medium.com/a-tc39-proposal-for-signals-f0bedd37a335&quot;&gt;blog post&lt;/a&gt; to learn more about it.&lt;/p&gt;
&lt;p&gt;TL;DR: &lt;code&gt;new Signal.State()&lt;/code&gt; would be the equivalent of &lt;code&gt;signal()&lt;/code&gt; in Angular.
&lt;code&gt;new Signal.Computed()&lt;/code&gt; would be the equivalent of &lt;code&gt;computed()&lt;/code&gt;.
There are no equivalents for &lt;code&gt;effect&lt;/code&gt;:
as all frameworks have slightly different needs, this is left out of the scope of the proposal, and frameworks can implement it as they see fit based on &lt;code&gt;new Signal.subtle.Watcher()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Fun fact: the current Signal &lt;a href=&quot;https://github.com/proposal-signals/signal-polyfill&quot;&gt;polyfill&lt;/a&gt; in the proposal is based on the Angular implementation!&lt;/p&gt;
&lt;h2&gt;Zoneless change detection&lt;/h2&gt;
&lt;p&gt;Angular v18 introduces a new way to trigger change detection.
Instead of relying on ZoneJS to know when something has possibly changed,
the framework can now schedule a change detection by itself.&lt;/p&gt;
&lt;p&gt;To do so, a new scheduler has been added to the framework (called &lt;code&gt;ChangeDetectionScheduler&lt;/code&gt;),
and this scheduler is internally used to trigger change detection.
This new scheduler is enabled by default in v18, even if you use ZoneJS.
However, the goal is to progressively move away from ZoneJS and rely only on this new scheduler.&lt;/p&gt;
&lt;p&gt;With this new scheduler, the framework no longer only relies on ZoneJS to trigger change detection.
Indeed, the new scheduler triggers a change detection when a host or template listener is triggered,
when a view is attached or removed, when an &lt;code&gt;async&lt;/code&gt; pipe detects a new emission,
when the &lt;code&gt;markForCheck()&lt;/code&gt; method is called, when you set a signal value, etc.
It does so by calling &lt;code&gt;ApplicationRef.tick()&lt;/code&gt; internally.&lt;/p&gt;
&lt;h3&gt;Opting out of the new scheduler&lt;/h3&gt;
&lt;p&gt;The new scheduler is enabled by default in v18.
This means that Angular gets notified of potential changes by ZoneJS (as it used to)
and by the new scheduler (when a signal is set, an &lt;code&gt;async&lt;/code&gt; pipe receives a new value, etc.).
The framework then runs the change detection.
This should not impact your application,
as Angular will only run the change detection once even if notified by several sources.
But if you want to opt out of the new scheduler,
you can use the &lt;code&gt;provideZoneChangeDetection()&lt;/code&gt; function with &lt;code&gt;ignoreChangesOutsideZone&lt;/code&gt; set to &lt;code&gt;true&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;bootstrapApplication&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(AppComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  providers&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // this restores the behavior of Angular before v18&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // and ignores the new scheduler notifications&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    provideZoneChangeDetection&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; ignoreChangesOutsideZone&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Experimental zoneless change detection&lt;/h3&gt;
&lt;p&gt;But you can also try to &lt;em&gt;only&lt;/em&gt; rely on this new scheduler, and no longer on ZoneJS, to trigger change detection.
This is an experimental feature, and you can enable it by using the provider function &lt;code&gt;provideExperimentalZonelessChangeDetection()&lt;/code&gt; in your application.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;bootstrapApplication&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(AppComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  providers&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // 👇&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    provideExperimentalZonelessChangeDetection&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When doing so, the framework will no longer rely on ZoneJS to trigger change detection.
So you can remove ZoneJS from your application if you want to 
(and if you have no dependencies that rely on it, of course).
In that case, you can remove &lt;code&gt;zone.js&lt;/code&gt; from the &lt;code&gt;polyfills&lt;/code&gt; in your &lt;code&gt;angular.json&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;It should work out of the box if all your components are &lt;code&gt;OnPush&lt;/code&gt; and/or rely on signals! 🚀&lt;/p&gt;
&lt;p&gt;I tried it on a small application fully written with signals and it worked like a charm.
Of course, this is not something we will be able to do in all applications,
but it&amp;#39;s a nice step forward towards a zoneless Angular.
In particular, if you use a component library that isn&amp;#39;t ready for zoneless support, you&amp;#39;ll have to wait until it is.
If you want to prepare your application for this new feature,
you can start by progressively moving your components to &lt;code&gt;OnPush&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Testing&lt;/h3&gt;
&lt;p&gt;Note that the &lt;code&gt;provideExperimentalZonelessChangeDetection&lt;/code&gt; function can also be used in tests,
so you can test your application without ZoneJS,
and make sure your components are correctly working with this new feature.&lt;/p&gt;
&lt;p&gt;You can currently add the provider in each test, or globally to all your tests by adding it in the &lt;code&gt;TestBed&lt;/code&gt; configuration,
in the &lt;code&gt;test.ts&lt;/code&gt; file of your application (this file is no longer generated in new projects, but you can add it back manually):&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;NgModule&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  providers&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;provideExperimentalZonelessChangeDetection&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ZonelessTestModule&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;getTestBed&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;initTestEnvironment&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  [BrowserDynamicTestingModule&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; ZonelessTestModule]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  platformBrowserDynamicTesting&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, instead of relying on &lt;code&gt;fixture.detectChanges()&lt;/code&gt;
that triggers the change detection, 
you can simply use &lt;code&gt;await fixture.whenStable()&lt;/code&gt; and let Angular trigger the change detection
(as it would when running the application).
This is because the &lt;code&gt;ComponentFixture&lt;/code&gt; used by the framework in zoneless mode
uses the &amp;quot;auto detect changes&amp;quot; strategy by default.&lt;/p&gt;
&lt;p&gt;So, similarly to using &lt;code&gt;OnPush&lt;/code&gt; in your components to prepare for the zoneless future,
a good way to prepare your tests is to progressively replace &lt;code&gt;detectChanges()&lt;/code&gt; with &lt;code&gt;await fixture.whenStable()&lt;/code&gt;
and enable &amp;quot;auto-detect changes&amp;quot; in your tests.&lt;/p&gt;
&lt;p&gt;This is something that has been existing for quite some time in Angular.
If you want to use it in your current tests, even without using &lt;code&gt;provideExperimentalZonelessChangeDetection&lt;/code&gt;,
you can either call &lt;code&gt;fixture.autoDetectChanges()&lt;/code&gt; at the beginning of your test,
or add the following provider to your test configuration:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;providers&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; provide&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; ComponentFixtureAutoDetect&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; useValue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#39;re probably going to update our ebook and the tests we provide in our online training to use this strategy.&lt;/p&gt;
&lt;p&gt;Note that some testing features that use ZoneJS are not supported with 
&lt;code&gt;provideExperimentalZonelessChangeDetection()&lt;/code&gt;, like &lt;code&gt;fakeAsync&lt;/code&gt; and &lt;code&gt;tick()&lt;/code&gt;.
If you need to fake time in your tests, you can use the &lt;code&gt;jasmine.clock&lt;/code&gt; APIs instead.&lt;/p&gt;
&lt;h3&gt;Debugging existing applications&lt;/h3&gt;
&lt;p&gt;If you want to check if your current application is ready for zoneless change detection,
you can use &lt;code&gt;provideExperimentalCheckNoChangesForDebug()&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;bootstrapApplication&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(AppComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  providers&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    provideZoneChangeDetection&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; eventCoalescing&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // or provideExperimentalZonelessChangeDetection()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    provideExperimentalCheckNoChangesForDebug&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      interval&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 1000&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // run change detection every second&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      useNgZoneOnStable&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // run it when the NgZone is stable as well&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      exhaustive&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // check all components&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will run a change detection every second and check if any component has been changed without triggering a change detection.
If such a change is detected, a &lt;code&gt;NG0100: ExpressionChangedAfterItHasBeenCheckedError&lt;/code&gt; error will be thrown in the console.
This should allow you to track down the components that need to be updated to work with zoneless change detection.&lt;/p&gt;
&lt;h3&gt;Zone.js status&lt;/h3&gt;
&lt;p&gt;ZoneJS is still a dependency of Angular and will be for a while.
It is now officially in maintenance mode, and will not ship new features,
but will still be maintained for bug fixes and security issues.&lt;/p&gt;
&lt;h2&gt;Fallback for ng-content&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;ng-content&amp;gt;&lt;/code&gt; is a powerful feature in Angular, but it has a cumbersome limitation: it can&amp;#39;t have fallback content.
This is no longer the case in Angular&amp;nbsp;v18!&lt;/p&gt;
&lt;p&gt;We can now add some content inside the &lt;code&gt;&amp;lt;ng-content&amp;gt;&lt;/code&gt; tag, and this content will be displayed if no content is projected in the component.&lt;/p&gt;
&lt;p&gt;For example, let&amp;#39;s consider a &lt;code&gt;CardComponent&lt;/code&gt; with a title and a content
that can be projected:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;card&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;card-body&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;h4&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;card-title&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;      &amp;#x3C;!-- 👇 If the title is not provided, we display a default title --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ng-content&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; select&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;.title&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Default title&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ng-content&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;h4&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;card-text&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ng-content&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; select&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;.content&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ng-content&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, if we use this component without providing a title, the default title will be displayed!&lt;/p&gt;
&lt;h2&gt;Forms events&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;AbstractControl&lt;/code&gt; class (the base class for form controls, groups, arrays, and records) now has a new property called &lt;code&gt;events&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This field is an observable that emits events when the control&amp;#39;s value, status, pristine state, or touched state changes.
It also emits when the form is reset or submitted.&lt;/p&gt;
&lt;p&gt;For example, let&amp;#39;s consider a form group for a user with a login and a password:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;fb &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; inject&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(NonNullableFormBuilder)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;userForm &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;fb&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;group&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Validators&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;required]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  password&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Validators&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;required]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  constructor&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;userForm&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;events&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;subscribe&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;      if&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; instanceof&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; TouchedChangeEvent&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;        console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Touched: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; event&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;touched&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; instanceof&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; PristineChangeEvent&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;        console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Pristine: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; event&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;pristine&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; instanceof&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; StatusChangeEvent&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;        console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Status: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; event&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; instanceof&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ValueChangeEvent&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;        console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Value: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; event&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; instanceof&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; FormResetEvent&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;        console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Form reset&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; instanceof&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; FormSubmitEvent&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;        console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Form submit&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, several types of events can be emitted:
&lt;code&gt;TouchedChangeEvent&lt;/code&gt;, &lt;code&gt;PristineChangeEvent&lt;/code&gt;, &lt;code&gt;StatusChangeEvent&lt;/code&gt;, &lt;code&gt;ValueChangeEvent&lt;/code&gt;, &lt;code&gt;FormResetEvent&lt;/code&gt; and &lt;code&gt;FormSubmitEvent&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If I enter a first character in the login field, the console will display:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Pristine: false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Value: Object { login: &quot;c&quot;, password: &quot;&quot; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Status: INVALID&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Touched: true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All events also have a &lt;code&gt;source&lt;/code&gt; property that contains the control that emitted the event
(here the login control). The &lt;code&gt;source&lt;/code&gt; contains the form itself for form reset and submission events.&lt;/p&gt;
&lt;h2&gt;Router and redirects&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;redirectTo&lt;/code&gt; property of a route now accepts a function instead of just a string.
Previously, we were only able to redirect our users to a static route
or a route with the same parameters.
The &lt;code&gt;RedirectFunction&lt;/code&gt; introduced in v18 allows us to access part of the &lt;code&gt;ActivatedRouteSnapshot&lt;/code&gt; to build the redirect URL.
I say &amp;quot;part of&amp;quot; because the activated route is not fully resolved when the function is called. For example, the resolvers haven&amp;#39;t run yet, the child routes aren&amp;#39;t matched, etc.
But we do have access to the parent route params or the query params for example,
which was not previously possible.
This function is also similar to guards, and is run in the environment injector:
this means you can inject services if needed.
The function can return a string or a &lt;code&gt;UrlTree&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;provideRouter&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;([&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    path&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;legacy-users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    redirectTo&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;redirectData&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;      const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; userService&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; inject&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;UserService&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;      const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; router&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; inject&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Router&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;      // You also have access to &apos;routeConfig&apos;, &apos;url&apos;, &apos;params&apos;, &apos;fragment&apos;,  &apos;data&apos;,  &apos;outlet&apos;, and &apos;title&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;      const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; queryParams&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; redirectData&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;queryParams&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;      // if the user is logged in, keep the query params&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;      if&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;userService&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;isLoggedIn&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; urlTree&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; router&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;parseUrl&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;/users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;        urlTree&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;queryParams&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; queryParams&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; urlTree&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;      return&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;/users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A similar improvement has been made in guards.
The &lt;code&gt;GuardResult&lt;/code&gt; type returned by a guard has been augmented from &lt;code&gt;boolean | UrlTree&lt;/code&gt; to &lt;code&gt;boolean | UrlTree | RedirectCommand&lt;/code&gt;.
A guard could already return an &lt;code&gt;UrlTree&lt;/code&gt; to redirect the user to another route,
but now it can also return a &lt;code&gt;RedirectCommand&lt;/code&gt; to redirect the user to another route with a specific navigation behavior, as a &lt;code&gt;RedirectCommand&lt;/code&gt; is an object
with two properties: &lt;code&gt;redirectTo&lt;/code&gt; (the &lt;code&gt;UrlTree&lt;/code&gt; to navigate to) and &lt;code&gt;navigationBehaviorOptions&lt;/code&gt; (the &lt;a href=&quot;https://angular.io/api/router/NavigationBehaviorOptions&quot;&gt;navigation behavior&lt;/a&gt; to use):&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;provideRouter&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;([&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    path&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    component&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; UsersComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    canActivate&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; userService&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; inject&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;UserService&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; userService&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;isLoggedIn&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; RedirectCommand&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;router&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;parseUrl&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;/login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;          state&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; requestedUrl&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;        }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;    ]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Resolvers can now also return a &lt;code&gt;RedirectCommand&lt;/code&gt;.
The first resolver to do so will trigger a redirect and cancel the current navigation.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;withNavigationErrorHandler()&lt;/code&gt; has also been updated to be able to return a &lt;code&gt;RedirectCommand&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;HttpClientModule deprecation&lt;/h2&gt;
&lt;p&gt;Now that the ecosystem is moving towards standalone components,
we&amp;#39;re starting to see the deprecation of the first Angular modules.
Starting with v18, &lt;code&gt;HttpClientModule&lt;/code&gt; (and &lt;code&gt;HttpClientTestingModule&lt;/code&gt;, &lt;code&gt;HttpClientXsrfModule&lt;/code&gt;, and &lt;code&gt;HttpClientJsonpModule&lt;/code&gt;) are deprecated.&lt;/p&gt;
&lt;p&gt;As you probably know, you can now use &lt;code&gt;provideHttpClient()&lt;/code&gt; (with options for XSRF or JSONP support) and &lt;code&gt;provideHttpClientTesting()&lt;/code&gt; as a replacement.&lt;/p&gt;
&lt;p&gt;But, as usual, the Angular team provides a schematic to help you migrate your application. When running &lt;code&gt;ng update @angular/core&lt;/code&gt;, you&amp;#39;ll be prompted to migrate your HTTP modules if you still have some in your application.&lt;/p&gt;
&lt;h2&gt;Internationalization&lt;/h2&gt;
&lt;p&gt;The utility functions offered by &lt;code&gt;@angular/common&lt;/code&gt; to work with locale data have been deprecated in favor of the &lt;code&gt;Intl&lt;/code&gt; API.
It is no longer recommended to use &lt;code&gt;getLocaleCurrencyCode()&lt;/code&gt;, &lt;code&gt;getLocaleDateFormat()&lt;/code&gt;,
&lt;code&gt;getLocaleFirstDayOfWeek()&lt;/code&gt;, etc.
Instead, you should use the &lt;code&gt;Intl&lt;/code&gt; API directly,
for example &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat&quot;&gt;Intl.DateTimeFormat&lt;/a&gt; to work with locale dates.&lt;/p&gt;
&lt;h2&gt;Server-Side Rendering&lt;/h2&gt;
&lt;p&gt;We have two new features in Angular v18 that are related to Server-Side Rendering (SSR).&lt;/p&gt;
&lt;h3&gt;SSR and replay events&lt;/h3&gt;
&lt;p&gt;It is now possible to record user interactions during the hydration phase,
and replay them when the application is fully loaded.
As you may know, the hydration phase is the phase where the server-rendered HTML
is transformed into a fully functional Angular application,
where listeners are added to the existing elements.&lt;/p&gt;
&lt;p&gt;But during this phase, the user can interact with the application,
and these interactions are lost (if the hydration process is not fast enough).&lt;/p&gt;
&lt;p&gt;So for some applications, it can be interesting to record these interactions
and replay them when the application is fully loaded.&lt;/p&gt;
&lt;p&gt;This used to be done via a project called &lt;em&gt;preboot&lt;/em&gt; in Angular,
but this project was no longer maintained.
Instead of reviving preboot, the Angular team decided to implement this feature directly in the framework.
But they did not start from scratch:
in fact, they used something that already existed inside Google, in the Wiz framework.
Wiz is not open-source, but it is widely used by Google for their applications (Google Search, Google Photos, etc.).
You can read about the ambitions of the Wiz and Angular teams to &amp;quot;merge&amp;quot; the two frameworks in this &lt;a href=&quot;https://medium.com/angular-blog/angular-and-wiz-are-better-together-91e633d8cd5a&quot;&gt;blog post on angular.io&lt;/a&gt;.
Wiz started to use the signals API from Angular (that&amp;#39;s why Youtube is now using Signals),
and now Angular is using the replay events feature from Wiz.
That&amp;#39;s why these two features are in a &lt;code&gt;packages/core/primitives&lt;/code&gt; directory in the Angular codebase:
they are part of Angular but are shared by the two frameworks.&lt;/p&gt;
&lt;p&gt;To enable this feature, you can use the &lt;code&gt;withEventReplay()&lt;/code&gt; (developer preview) function in your server-side rendering configuration:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;providers&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  provideClientHydration&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;withEventReplay&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When doing so, Angular will add a JS script at the top of your HTML page,
whose job is to replay events that happened during the hydration phase.
To do so, it adds a listener at the root of the document,
and listens to a set of events that can happen on the page
using &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#event_delegation&quot;&gt;event delegation&lt;/a&gt;.
It does know which events it needs to listen to,
as Angular collected them when rendering the page on the server.
So for example, if you render a page that contains elements which have a &lt;code&gt;(click)&lt;/code&gt; or a &lt;code&gt;(dblclick)&lt;/code&gt; handler,
Angular will add listeners for these events:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;window&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;__jsaction_bootstrap&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ngContracts&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; document&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ng&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;click&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;dblclick&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the application is loaded and stable,
the script then replays the events that happened during the hydration phase,
thus triggering the same actions as the user did.
Quite a nice feature, even if it is probably useful only for some applications.&lt;/p&gt;
&lt;h3&gt;SSR and Internationalization&lt;/h3&gt;
&lt;p&gt;The Angular SSR support is improving with each version.
One year ago, Angular v16 introduced progressive hydration,
as we explained in this &lt;a href=&quot;/2023/05/03/what-is-new-angular-16.0&quot;&gt;blog post&lt;/a&gt;.
There was one missing feature at the time:
the internationalization support.
Angular would skip the elements marked with &lt;code&gt;i18n&lt;/code&gt; during SSR.
This is now solved in v18! 
If your application uses the builtin i18n support of the framework,
you can now use SSR.
The support is in developer preview, and can be enabled with &lt;code&gt;withI18nSupport()&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Angular CLI&lt;/h2&gt;
&lt;p&gt;The CLI has also been released in version v18, with some notable features.&lt;/p&gt;
&lt;h3&gt;Performance improvements&lt;/h3&gt;
&lt;p&gt;The CLI now builds projects with a larger number of components faster.
The commit mentions some &lt;a href=&quot;https://github.com/angular/angular-cli/commit/0a4943556ffa3c0888aa09f96d7508af56db637e&quot;&gt;really nice gains&lt;/a&gt; but I was not able to reproduce them in my experiments on large projects. &lt;/p&gt;
&lt;h3&gt;ng dev&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;ng serve&lt;/code&gt; command is now aliased to &lt;code&gt;ng dev&lt;/code&gt; (in addition to the existing &lt;code&gt;ng s&lt;/code&gt;).
This aligns with the Vite ecosystem, where the development server is usually started using &lt;code&gt;npm run dev&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Speaking of commands, the &lt;code&gt;ng doc&lt;/code&gt; command has been removed from the CLI in v18.&lt;/p&gt;
&lt;h3&gt;New build package&lt;/h3&gt;
&lt;p&gt;The Angular CLI now has a new package for building applications: &lt;code&gt;@angular/build&lt;/code&gt;.
It contains the esbuild/Vite builders, that were previously in the &lt;code&gt;@angular-devkit/build-angular&lt;/code&gt; package.
This allows the new package to only have Vite and ESBuild as dependencies,
and not Webpack.
The &lt;code&gt;serve&lt;/code&gt;/&lt;code&gt;build&lt;/code&gt;/&lt;code&gt;extract-i18n&lt;/code&gt; builders are now in this new package.
The &lt;code&gt;@angular-devkit/build-angular&lt;/code&gt; package can still be used,
as it provides an alias to the now-moved builders.&lt;/p&gt;
&lt;p&gt;You&amp;#39;ll notice that an optional migration can be run when updating your application to v18, to update your &lt;code&gt;angular.json&lt;/code&gt; file to use the new package 
(where &lt;code&gt;@angular-devkit/build-angular&lt;/code&gt; is replaced by &lt;code&gt;@angular/build&lt;/code&gt;)
and update your &lt;code&gt;package.json&lt;/code&gt; accordingly (to add &lt;code&gt;@angular/build&lt;/code&gt; and remove &lt;code&gt;@angular-devkit/build-angular&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;This will only be done if you don&amp;#39;t use any Webpack-based builders in your applications,
so the migration does nothing if you have tests using Karma for example (as they run using Webpack).&lt;/p&gt;
&lt;h3&gt;Less and PostCSS dependencies&lt;/h3&gt;
&lt;p&gt;The CLI supports Sass, Less, and PostCSS out of the box,
and until now, these dependencies were installed in your &lt;code&gt;node_modules&lt;/code&gt;
when creating a new application (even if you were not using these dependencies).&lt;/p&gt;
&lt;p&gt;Less and PostCSS are now optional dependencies for the new &lt;code&gt;@angular/build&lt;/code&gt; package and need to be installed explicitly if you switch to the new package.&lt;/p&gt;
&lt;p&gt;When you update your application to v18, these dependencies will be added automatically by &lt;code&gt;ng update&lt;/code&gt; if you choose to switch to &lt;code&gt;@angular/build&lt;/code&gt; (and if you&amp;#39;re using them of course).&lt;/p&gt;
&lt;h3&gt;Native async/await in zoneless applications&lt;/h3&gt;
&lt;p&gt;ZoneJS has a particularity: it can&amp;#39;t work with async/await.
So you may not know it, but every time you use async/await in your application,
your code is transformed by the CLI to use &amp;quot;regular&amp;quot; promises.
This is called downleveling, as it transforms ES2017 code (async/await) into ES2015 code (regular promises).&lt;/p&gt;
&lt;p&gt;As we are now able to build applications without ZoneJS (even if it is still experimental),
the CLI doesn&amp;#39;t downlevel async/await when &lt;code&gt;zone.js&lt;/code&gt; is not in the application polyfills.
This should make the build a tiny bit faster and lighter in that case.&lt;/p&gt;
&lt;h3&gt;New project skeleton updates&lt;/h3&gt;
&lt;p&gt;If you want to upgrade to v18 without pain (or to any other version, by the way), I have created a Github project to help: &lt;a href=&quot;https://github.com/cexbrayat/angular-cli-diff&quot;&gt;angular-cli-diff&lt;/a&gt;. Choose the version you&amp;#39;re currently using (17.3.0 for example), and the target version (18.0.0 for example), and it gives you a diff of all files created by the CLI: &lt;a href=&quot;https://github.com/cexbrayat/angular-cli-diff/compare/17.3.0...18.0.0&quot;&gt;angular-cli-diff/compare/17.3.0...18.0.0&lt;/a&gt;.
It can be a great help along with the official &lt;code&gt;ng update @angular/core @angular/cli&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;You&amp;#39;ll notice that the &lt;code&gt;assets&lt;/code&gt; folder has been replaced by a &lt;code&gt;public&lt;/code&gt; folder in new projects.
You&amp;#39;ll also note that the &lt;code&gt;app.config.ts&lt;/code&gt; file now contains the &lt;code&gt;provideZoneChangeDetection()&lt;/code&gt; provider by default with the &lt;code&gt;eventCoalescing&lt;/code&gt; option set to &lt;code&gt;true&lt;/code&gt; (which avoids the change detection being triggered several times by ZoneJS when an event bubbles and is listened to by several template listeners). &lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;That&amp;#39;s all for this release.
v19 will probably be dedicated to stabilizing the signals APIs introduced these past months.
We should also see a new feature to declare variables in the template itself, using &lt;code&gt;@let&lt;/code&gt;, as well as an option to switch to Intl-based internationalization.
Stay tuned!&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>What&apos;s new in Angular 17.3?</title>
    <link href="https://blog.ninja-squad.com/2024/03/13/what-is-new-angular-17.3"/>
    <updated>2024-03-13T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2024/03/13/what-is-new-angular-17.3</id>
    <content type="html">
      &lt;p&gt;Angular&amp;nbsp;17.3.0 is here!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;a href=&quot;https://github.com/angular/angular/releases/tag/17.3.0&quot;&gt;
    &lt;img class=&quot;img-fluid&quot; style=&quot;max-width: 60%&quot; src=&quot;/assets/images/angular_gradient.webp&quot; alt=&quot;Angular logo&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;This is a minor release with some nice features: let&amp;#39;s dive in!&lt;/p&gt;
&lt;h2&gt;TypeScript 5.4 support&lt;/h2&gt;
&lt;p&gt;Angular v17.3 now supports TypeScript 5.4. This means that you can use the latest version of TypeScript in your Angular applications. You can check out the &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-4/&quot;&gt;TypeScript 5.4 release notes&lt;/a&gt; to learn more about the new features.&lt;/p&gt;
&lt;h2&gt;New template compiler&lt;/h2&gt;
&lt;p&gt;Angular now uses a new template compiler! The work on this compiler started more than a year ago and has been done in parallel with the other features we saw in the previous releases to eventually pass all of the existing tests. It&amp;#39;s now the case, and this new compiler is now the default in Angular 17.3.&lt;/p&gt;
&lt;p&gt;This compiler is based on an intermediate representation of template operations,
a common concept in compilers, for example in LLVM.
This &lt;em&gt;IR&lt;/em&gt; semantically encodes what needs to happen at runtime to render and change-detect the template.
Using an &lt;em&gt;IR&lt;/em&gt; allows for different concerns of template compilation to be processed independently,
which was not the case with the previous implementation.
This new compiler is easier to maintain and extend,
so it is a great foundation for future improvements in the framework.&lt;/p&gt;
&lt;p&gt;Note that the compiler emits the same code as the previous one,
so you should not see any difference in the generated code.&lt;/p&gt;
&lt;h2&gt;output functions&lt;/h2&gt;
&lt;p&gt;A new (developer preview) feature was added to allow the declaration
of outputs similarly to the &lt;code&gt;input()&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;As for inputs, you can use the &lt;code&gt;output()&lt;/code&gt; function to define an output:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;ponySelected &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; output&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;PonyModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// ^? OutputEmitterRef&amp;#x3C;PonyModel&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;output()&lt;/code&gt; function returns an &lt;code&gt;OutputEmitterRef&amp;lt;T&amp;gt;&lt;/code&gt;
that can be used to emit values.
&lt;code&gt;OutputEmitterRef&lt;/code&gt; is an Angular class,
really similar to a simplified &lt;code&gt;EventEmitter&lt;/code&gt;
but that does not rely on &lt;code&gt;RxJS&lt;/code&gt;
(to limit the coupling of Angular with RxJS).&lt;/p&gt;
&lt;p&gt;The function accepts a parameter to specify options,
the only one available for now is &lt;code&gt;alias&lt;/code&gt; to alias the output.&lt;/p&gt;
&lt;p&gt;As with &lt;code&gt;EventEmitter&lt;/code&gt;, you can use the &lt;code&gt;emit()&lt;/code&gt; method to emit a value:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;ponySelected &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; output&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;PonyModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// ^? OutputEmitterRef&amp;#x3C;PonyModel&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;select&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;ponySelected&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;emit&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;ponyModel&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also declare an output without a generic type,
and the &lt;code&gt;OutputEmitterRef&lt;/code&gt; will be of type &lt;code&gt;OutputEmitterRef&amp;lt;void&amp;gt;&lt;/code&gt;.
You can then call &lt;code&gt;emit()&lt;/code&gt; without a parameter on such an output.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;OutputEmitterRef&lt;/code&gt; also exposes a subscribe method
to manually subscribe to the output.
This is not something you’ll do often, but it can be handy in some cases.
If you manually subscribe to an output,
you’ll have to manually unsubscribe as well.
To do so, the subscribe method returns an &lt;code&gt;OutputRefSubscription&lt;/code&gt; object with an &lt;code&gt;unsubscribe&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;Two new functions have been added to the &lt;code&gt;rxjs-interop&lt;/code&gt; package to convert an output to an observable,
and an observable to an output.&lt;/p&gt;
&lt;p&gt;Angular always had the capability of using observables other than &lt;code&gt;EventEmitter&lt;/code&gt; for outputs.
This is not something that is largely used, but it’s possible.
The new &lt;code&gt;outputFromObservable&lt;/code&gt; function allows you to convert an observable to an output:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;ponyRunning$ &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; BehaviorSubject&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;ponyRunning &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; outputFromObservable&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;ponyRunning$)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// ^? OutputRef&amp;#x3C;boolean&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;outputFromObservable&lt;/code&gt; function returns an &lt;code&gt;OutputRef&amp;lt;T&amp;gt;&lt;/code&gt;, and not an &lt;code&gt;OutputEmitterRef&amp;lt;T&amp;gt;&lt;/code&gt;,
as you can’t emit values on an output created from an observable.
The output emits every event that is emitted by the observable.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;startRunning&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;ponyRunning$&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is also possible to convert an output to an observable using the &lt;code&gt;outputToObservable&lt;/code&gt; function if needed.
You can then use &lt;code&gt;.pipe()&lt;/code&gt; and all the RxJS operators on the converted output.&lt;/p&gt;
&lt;p&gt;These interoperability functions will probably be rarely used.
&lt;code&gt;output()&lt;/code&gt;, on the other hand, will become the recommended way to declare outputs in Angular components.&lt;/p&gt;
&lt;h2&gt;HostAttributeToken&lt;/h2&gt;
&lt;p&gt;Angular has always allowed to inject the value of an attribute of the host element.
For example, to get the type of an input, you can use:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Directive&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  selector&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  standalone&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; InputAttrDirective&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  constructor&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;(@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Attribute&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // type would be &apos;text&apos; if `&amp;#x3C;input type=&quot;text&quot; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since Angular v14, injection can be done via the &lt;code&gt;inject()&lt;/code&gt; function as well,
but there was no option to get an attribute value with it.&lt;/p&gt;
&lt;p&gt;This is now possible by using a special class &lt;code&gt;HostAttributeToken&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;type &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; inject&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; HostAttributeToken&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that &lt;code&gt;inject&lt;/code&gt; throws if the attribute is not found (unless you pass a second argument &lt;code&gt;{ optional: true }&lt;/code&gt;).&lt;/p&gt;
&lt;h2&gt;RouterTestingModule deprecation&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;RouterTestingModule&lt;/code&gt; is now deprecated.
It is now recommended to &lt;code&gt;provideRouter()&lt;/code&gt; in the &lt;code&gt;TestBed&lt;/code&gt; configuration instead.&lt;/p&gt;
&lt;h2&gt;New router types&lt;/h2&gt;
&lt;p&gt;The router now has new types to model the result of guards and resolvers.&lt;/p&gt;
&lt;p&gt;For example, the CanActivate guard was declared like this:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; CanActivateFn&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;route&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ActivatedRouteSnapshot&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; state&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; RouterStateSnapshot&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; Observable&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; UrlTree&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; Promise&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; UrlTree&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; boolean&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; UrlTree&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is because the guard can return a boolean to allow or forbid the navigation, or an &lt;code&gt;UrlTree&lt;/code&gt; to trigger a redirection to another route. This result can be synchronous or asynchronous.&lt;/p&gt;
&lt;p&gt;The signature has been updated to:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; CanActivateFn&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;route&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ActivatedRouteSnapshot&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; state&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; RouterStateSnapshot&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; MaybeAsync&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;GuardResult&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;GuardResult&lt;/code&gt; is a new type equal to &lt;code&gt;boolean | UrlTree&lt;/code&gt;,
and &lt;code&gt;MaybeAsync&amp;lt;T&amp;gt;&lt;/code&gt; is a new generic type equal to &lt;code&gt;T | Observable&amp;lt;T&amp;gt; | Promise&amp;lt;T&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A resolver function now also returns a &lt;code&gt;MaybeAsync&amp;lt;T&amp;gt;&lt;/code&gt;.
You can keep using the older signatures but the new ones are more concise.&lt;/p&gt;
&lt;h2&gt;Angular CLI&lt;/h2&gt;
&lt;p&gt;Angular CLI v17.3 doesn&amp;#39;t bring a lot of new features,
but we can note that &lt;code&gt;deployUrl&lt;/code&gt; is now supported in the application builder.
It was initially marked as deprecated but was re-introduced after community feedback.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;That&amp;#39;s all for this release.
The next stop is v18, where we should see some developer preview features becoming stable.
Stay tuned!&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>What&apos;s new in Angular 17.2?</title>
    <link href="https://blog.ninja-squad.com/2024/02/14/what-is-new-angular-17.2"/>
    <updated>2024-02-14T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2024/02/14/what-is-new-angular-17.2</id>
    <content type="html">
      &lt;p&gt;Angular&amp;nbsp;17.2.0 is here!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;a href=&quot;https://github.com/angular/angular/releases/tag/17.2.0&quot;&gt;
    &lt;img class=&quot;img-fluid&quot; style=&quot;max-width: 60%&quot; src=&quot;/assets/images/angular_gradient.webp&quot; alt=&quot;Angular logo&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;This is a minor release with some nice features: let&amp;#39;s dive in!&lt;/p&gt;
&lt;h2&gt;Queries as signals&lt;/h2&gt;
&lt;p&gt;A new developer preview feature has been added to allow the use of queries as signals. &lt;code&gt;viewChild()&lt;/code&gt;, &lt;code&gt;viewChildren()&lt;/code&gt;, &lt;code&gt;contentChild()&lt;/code&gt;, and &lt;code&gt;contentChildren()&lt;/code&gt; functions have been added in @angular/core and return signals.&lt;/p&gt;
&lt;p&gt;Let’s go through a few examples.&lt;/p&gt;
&lt;p&gt;You can use viewChild to query the template:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// &amp;#x3C;canvas #chart&gt;&amp;#x3C;/canvas&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;canvas &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; viewChild&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ElementRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;HTMLCanvasElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;chart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// ^? Signal&amp;#x3C;ElementRef&amp;#x3C;HTMLCanvasElement&gt; | undefined&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// &amp;#x3C;form&gt;&amp;#x3C;/form&gt; with FormsModule&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;form &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; viewChild&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(NgForm)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// ^? Signal&amp;#x3C;NgForm | undefined&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the return type is a Signal containing the queried &lt;code&gt;ElementRef&amp;lt;HTMLElement&amp;gt;&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;, or the queried component/directive or &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can specify that the queried element is required to get rid of &lt;code&gt;undefined&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;canvas &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; viewChild&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ElementRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;HTMLCanvasElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;chart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// ^? Signal&amp;#x3C;ElementRef&amp;#x3C;HTMLCanvasElement&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the element is not found, you’ll have a runtime error:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&apos;NG0951: Child query result is required but no value is available.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Find more at https://angular.io/errors/NG0951&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This error can also happen if you try to access the query result too soon, for example in the constructor of the component. You can access the query result in the &lt;code&gt;ngAfterViewInit&lt;/code&gt;/&lt;code&gt;ngAfterViewChecked&lt;/code&gt; lifecycle hooks, or in the &lt;code&gt;afterNextRender&lt;/code&gt;/&lt;code&gt;afterRender&lt;/code&gt; functions.&lt;/p&gt;
&lt;p&gt;You can also use &lt;code&gt;viewChildren&lt;/code&gt; to query multiple elements. In that case, you get a Signal containing a readonly array of elements, or an empty array if no element is found (we no longer need QueryList \o/):
chart.component.ts&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;canvases &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; viewChildren&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ElementRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;HTMLCanvasElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;chart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// ^? Signal&amp;#x3C;ReadonlyArray&amp;#x3C;ElementRef&amp;#x3C;HTMLCanvasElement&gt;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The functions accept the same option as &lt;code&gt;@ViewChild&lt;/code&gt; and &lt;code&gt;@ViewChildren&lt;/code&gt;, so you can specify the &lt;code&gt;read&lt;/code&gt; option to query a directive or provider on an element.&lt;/p&gt;
&lt;p&gt;As you can imagine, the same is possible for &lt;code&gt;contentChild&lt;/code&gt; and &lt;code&gt;contentChildren&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For example, if we want to build a &lt;code&gt;TabsComponent&lt;/code&gt; that can be used like this:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-tabs&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-tab&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; title&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Races&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-tab&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; title&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;About&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-tabs&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can build a &lt;code&gt;TabDirective&lt;/code&gt; to represent a tab:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Directive&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  selector&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ns-tab&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  standalone&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; TabDirective&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  title&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;then build the &lt;code&gt;TabsComponent&lt;/code&gt; with &lt;code&gt;contentChildren&lt;/code&gt; to query the directives:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  selector&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ns-tabs&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; `&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;nav nav-tabs&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;      @for&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (tab &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; tabs&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; track&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; tab) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;        &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;nav-item&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;          &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;nav-link&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; tab&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;        &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;  `&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  standalone&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; TabsComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  tabs&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; contentChildren&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(TabDirective)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // ^? Signal&amp;#x3C;ReadonlyArray&amp;#x3C;TabDirective&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As for the &lt;code&gt;@ViewChild&lt;/code&gt;/&lt;code&gt;@ViewChildren&lt;/code&gt; decorators, we can specify the descendants option to query the tab directives that are not direct children of &lt;code&gt;TabsComponent&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;tabs &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; contentChildren&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(TabDirective&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; descendants&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// ^? Signal&amp;#x3C;ReadonlyArray&amp;#x3C;TabDirective&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-tabs&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-tab&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; title&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Races&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-tabgroup&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-tab&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; title&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;About&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-tabgroup&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-tabs&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As &lt;code&gt;viewChild&lt;/code&gt;, &lt;code&gt;contentChild&lt;/code&gt; can be required.&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;model&lt;/code&gt; signal&lt;/h2&gt;
&lt;p&gt;Signals also allow a fresh take on existing patterns. As you probably know, Angular allows a &amp;quot;banana in a box&amp;quot; syntax for two-way binding. This is mostly used with &lt;code&gt;ngModel&lt;/code&gt; to bind a form control to a component property:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [(ngModel)]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;user.login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Under the hood, this is because the &lt;code&gt;ngModel&lt;/code&gt; directive has a &lt;code&gt;ngModel&lt;/code&gt; input and a &lt;code&gt;ngModelChange&lt;/code&gt; output.&lt;/p&gt;
&lt;p&gt;So the banana in a box syntax is just syntactic sugar for the following:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [ngModel]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;user.login&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; (ngModelChange)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;user.login = $event&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The syntax is, in fact, general and can be used with any component or directive that has an input named &lt;code&gt;something&lt;/code&gt; and an output named &lt;code&gt;somethingChange&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can leverage this in your own components and directives, for example, to build a pagination component:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) collectionSize&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) pageSize&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) page&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Output&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;() pageChange &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; EventEmitter&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;pages&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; []&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;ngOnChanges&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(): &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;pages&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;computePages&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;goToPage&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(page: number) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;pageChange&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;emit&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;page&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;private &lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;computePages&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; length&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Math&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;ceil&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;collectionSize&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;pageSize&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;},&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The component receives the collection, the page size, and the current page as inputs, and emits the new page when the user clicks on a button.&lt;/p&gt;
&lt;p&gt;Every time an input changes, the component recomputes the buttons to display.
The template uses a for loop to display the buttons:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@for&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (pageNumber &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; pages&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; track&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; pageNumber) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [class.active]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;page === pageNumber&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; (click)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;goToPage(pageNumber)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    {{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; pageNumber &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The component can then be used like:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-pagination&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [(page)]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;page&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [collectionSize]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;collectionSize&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [pageSize]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;pageSize&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-pagination&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that &lt;code&gt;page&lt;/code&gt; can be a number or a signal of a number,
the framework will handle it correctly.&lt;/p&gt;
&lt;p&gt;The pagination component can be rewritten using signals,
and the brand new &lt;code&gt;model()&lt;/code&gt; function:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;collectionSize &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;pageSize &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;pages &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; computed&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;computePages&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;page &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; model&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// ^? ModelSignal&amp;#x3C;number&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;goToPage&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(page: number) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;page&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;page&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;private &lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;computePages&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; length&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Math&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;ceil&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;collectionSize&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;pageSize&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;},&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, a &lt;code&gt;model()&lt;/code&gt; function is used to define the input/output pair, and the output emission is done using the &lt;code&gt;set()&lt;/code&gt; method of the signal.&lt;/p&gt;
&lt;p&gt;A model can be required, or can have a default value, or can be aliased, as it is the case for inputs. It can’t be transformed though. If you use an alias, the output will be aliased as well.&lt;/p&gt;
&lt;p&gt;If you try to access the value of the model before it has been set, for example in the constructor of the component, then you’ll have a runtime error:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&apos;NG0952: Model is required but no value is available yet.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Find more at https://angular.io/errors/NG0952&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Defer testing&lt;/h2&gt;
&lt;p&gt;The default behavior of the &lt;code&gt;TestBed&lt;/code&gt; 
for testing components using &lt;code&gt;@defer&lt;/code&gt; blocks has changed from
&lt;code&gt;Manual&lt;/code&gt; to &lt;code&gt;Playthrough&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Check out our blog post about &lt;a href=&quot;https://blog.ninja-squad.com/2023/11/09/what-is-new-angular-17.0/&quot;&gt;defer&lt;/a&gt; for more details.&lt;/p&gt;
&lt;h2&gt;NgOptimizedImage&lt;/h2&gt;
&lt;p&gt;The NgOptimizedImage directive
(check out &lt;a href=&quot;/2022/08/26/what-is-new-angular-14.2&quot;&gt;our blog post&lt;/a&gt; about it)
can now automatically display a placeholder while the image is loading,
if the provider supports automatic image resizing.&lt;/p&gt;
&lt;p&gt;This can be enabled by adding a &lt;code&gt;placeholder&lt;/code&gt; attribute to the directive:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;img&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; ngSrc&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;logo.jpg&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; placeholder&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The placeholder is 30px by 30px by default, but you can customize it.
It is displayed slightly blurred to give a hint to the user that the image is loading. The blur effect can be disabled with &lt;code&gt;[placeholderConfig]=&amp;quot;{ blur: false }&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Another new feature is the ability to use Netlify as a provider,
joining the existing Cloudflare, Cloudinary, ImageKit, and Imgix providers.&lt;/p&gt;
&lt;h2&gt;Angular CLI&lt;/h2&gt;
&lt;h3&gt;define support&lt;/h3&gt;
&lt;p&gt;The CLI now supports a new option named &lt;code&gt;define&lt;/code&gt; in the &lt;code&gt;build&lt;/code&gt; target.
It is similar to what the &lt;a href=&quot;https://esbuild.github.io/api/#define&quot;&gt;esbuild plugin of the same name&lt;/a&gt; does:
you can define constants that will be replaced with the specified value in TS and JS code,
including in libraries.&lt;/p&gt;
&lt;p&gt;You can for example define a BASE_URL that will be replaced with the value of &lt;code&gt;https://api.example.com&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;builder&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;@angular-devkit/build-angular:application&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;define&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &quot;&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;BASE_URL&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;&apos;https://api.example.com&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can then use it in your code:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;`${&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;BASE_URL&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;/users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;TypeScript needs to know that this constant exists (as you don&amp;#39;t import it),
so you need to declare it in a &lt;code&gt;d.ts&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;declare&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; BASE_URL&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can be an alternative to the environment files, and it can be even more powerful as the constant is also replaced in libraries.&lt;/p&gt;
&lt;h3&gt;Bun support&lt;/h3&gt;
&lt;p&gt;You can now use &lt;a href=&quot;https://bun.sh/&quot;&gt;Bun&lt;/a&gt; as a package manager for your Angular CLI projects, in addition to npm, yarn, pnpm and cnpm.
It will be automatically detected, or can be forced with &lt;code&gt;--package-manager=bun&lt;/code&gt;
when generating a new project.&lt;/p&gt;
&lt;h3&gt;clearScreen option&lt;/h3&gt;
&lt;p&gt;A new option is now supported in the application builder to clear the screen before rebuilding the application.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;builder&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;@angular-devkit/build-angular:application&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;clearScreen&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You then only see the output of the current build,
and not from the previous one.&lt;/p&gt;
&lt;h3&gt;Abbreviated build targets&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;angular.json&lt;/code&gt; file now supports abbreviated build targets.
For example, you currently have something like this in your project:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;serve&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;builder&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;@angular-devkit/build-angular:dev-server&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;configurations&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;development&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &quot;&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;buildTarget&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;app:build:development&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This means that &lt;code&gt;ng serve&lt;/code&gt; uses the &lt;code&gt;app:build:development&lt;/code&gt; target to build the application.&lt;/p&gt;
&lt;p&gt;This can now be abbreviated to:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;serve&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;builder&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;@angular-devkit/build-angular:dev-server&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;configurations&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;development&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &quot;&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;buildTarget&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;::development&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;PostCSS support&lt;/h3&gt;
&lt;p&gt;The application builder now supports PostCSS, a tool for transforming CSS with JavaScript plugins. You just have to add a &lt;code&gt;postcss.config.json&lt;/code&gt; or &lt;code&gt;.postcssrc.json&lt;/code&gt; file to your project and the CLI will pick it up.&lt;/p&gt;
&lt;h3&gt;JSON build logs&lt;/h3&gt;
&lt;p&gt;The CLI now supports a new option to output the build logs in JSON format. This can be useful to integrate the build logs in other tools.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;NG_BUILD_LOGS_JSON=1 ng build&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;That&amp;#39;s all for this release, stay tuned!&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>What&apos;s new in Angular 17.1?</title>
    <link href="https://blog.ninja-squad.com/2024/01/17/what-is-new-angular-17.1"/>
    <updated>2024-01-17T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2024/01/17/what-is-new-angular-17.1</id>
    <content type="html">
      &lt;p&gt;Angular&amp;nbsp;17.1.0 is here!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;a href=&quot;https://github.com/angular/angular/releases/tag/17.1.0&quot;&gt;
    &lt;img class=&quot;img-fluid&quot; style=&quot;max-width: 60%&quot; src=&quot;/assets/images/angular_gradient.webp&quot; alt=&quot;Angular logo&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;This is a minor release with some nice features: let&amp;#39;s dive in!&lt;/p&gt;
&lt;h2&gt;TypeScript 5.3 support&lt;/h2&gt;
&lt;p&gt;Angular v17.1 now supports TypeScript 5.3. This means that you can use the latest version of TypeScript in your Angular applications. You can check out the &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-3/&quot;&gt;TypeScript 5.3 release notes&lt;/a&gt; to learn more about the new features.&lt;/p&gt;
&lt;h2&gt;Inputs as signals&lt;/h2&gt;
&lt;p&gt;In Angular v17.1, a new feature was added to allow the use of inputs as signals.
This is a first step towards signal-based components.
The framework team added an &lt;code&gt;input()&lt;/code&gt; function in &lt;code&gt;@angular/core&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  standalone&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  selector&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ns-pony&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; `&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    @if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;ponyModel&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ponyModel&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;figure&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;        &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;img&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [src]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;imageUrl()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [alt]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ponyModel.name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;        &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;figcaption&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; ponyModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;figcaption&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;figure&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;  `&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; PonyComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  ponyModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;PonyModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  imageUrl&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; computed&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; `&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;assets/pony-&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ponyModel&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;!.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;color&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;.gif&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see in the example above, the &lt;code&gt;input()&lt;/code&gt; function returns a signal,
that can be used in the template or in computed values
(which would be the modern equivalent of &lt;code&gt;ngOnChanges&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;It can be undefined though,
hence the &lt;code&gt;@if&lt;/code&gt; in the template and the &lt;code&gt;!&lt;/code&gt; in the computed value.&lt;/p&gt;
&lt;p&gt;If an input is mandatory,
you can use the &lt;code&gt;input.required()&lt;/code&gt; version of the function:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  standalone&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  selector&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ns-pony&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; `&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;figure&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;img&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [src]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;imageUrl()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [alt]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ponyModel().name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;figcaption&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; ponyModel&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;figcaption&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;figure&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;  `&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; PonyComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  ponyModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;PonyModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  imageUrl&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; computed&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; `&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;assets/pony-&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ponyModel&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;color&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;.gif&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also provide a default value, an alias, and a transformer function.
Here the &lt;code&gt;ponySpeed&lt;/code&gt; field is aliased as &lt;code&gt;speed&lt;/code&gt;,
provided with a default value, and transformed to a number (even if the input is a string):&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;ponySpeed &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; input&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  alias&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;speed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  transform&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; numberAttribute&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also use the signal as the source of an observable,
to trigger an action when the input changes.
For example, to fetch data from a server:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; PonyComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  ponyService&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; inject&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(PonyService)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  ponyId&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // entity fetched from the server every time the ponyId changes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  ponyModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; toSignal&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;toObservable&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;ponyId)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;pipe&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;switchMap&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;ponyService&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(id))))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  imageUrl&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; computed&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; `&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;assets/pony-&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ponyModel&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;!.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;color&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;.gif&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When coupled with the recent addition to the router called &amp;quot;Component Input Binding&amp;quot;,
where the router binds the route parameters to the inputs of a component,
it can lead to an interesting pattern.
Note that the input &lt;code&gt;transform&lt;/code&gt; is necessary as the router parameters are strings:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;ponyId &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  transform&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; numberAttribute&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This behavior is enabled via &lt;code&gt;withComponentInputBinding&lt;/code&gt; in the router configuration:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;provideRouter&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      path&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;pony/:ponyId&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      component&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; PonyComponent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  ]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  withComponentInputBinding&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Zoneless change detection&lt;/h2&gt;
&lt;p&gt;The framework is making progress towards zoneless change detection.
A new private API called &lt;code&gt;ɵprovideZonelessChangeDetection&lt;/code&gt; was added to &lt;code&gt;@angular/core&lt;/code&gt;.
When you add this provider to your application,
the framework no longer relies on Zone.js for change detection (and you can remove it from the application).&lt;/p&gt;
&lt;p&gt;So how does it work?
Every time an event is fired, an input is set, an output emits a value, an &lt;code&gt;async&lt;/code&gt; pipe receives a value, a signal is set, &lt;code&gt;markForCheck&lt;/code&gt; is called, etc.,
the framework notifies an internal scheduler that something happened.
It then runs the change detection on the component marked as dirty.
But this doesn&amp;#39;t catch what Zone.js usually does:
a &lt;code&gt;setTimeout&lt;/code&gt;, a &lt;code&gt;setInterval&lt;/code&gt;, a &lt;code&gt;Promise&lt;/code&gt;, an &lt;code&gt;XMLHttpRequest&lt;/code&gt;, etc.&lt;/p&gt;
&lt;p&gt;But that shouldn&amp;#39;t be a problem because the idea is that when a &lt;code&gt;setTimeout&lt;/code&gt;, &lt;code&gt;setInterval&lt;/code&gt; or &lt;code&gt;XMLHttpRequest&lt;/code&gt; callback is triggered, and you want it to update the state of the application, you should do it by modifying a signal, which will in turn trigger change detection.&lt;/p&gt;
&lt;p&gt;This is far from being complete, as the &amp;quot;private API&amp;quot; part suggests.
However, it indicates that the framework is making progress towards zoneless change detection.&lt;/p&gt;
&lt;h2&gt;Router&lt;/h2&gt;
&lt;p&gt;The router now has an &lt;code&gt;info&lt;/code&gt; option in the &lt;code&gt;NavigationExtras&lt;/code&gt; 
that can be used to store information about the navigation.
Unlike the &lt;code&gt;state&lt;/code&gt; option,
this information is not persisted in the session history.
The &lt;code&gt;RouterLink&lt;/code&gt; directive now supports this option as well:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [routerLink]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;[&apos;/pony&apos;, pony.id]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [info]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;{ ponyName: pony.name }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; pony&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Control flow migration&lt;/h2&gt;
&lt;p&gt;The control flow migration is still experimental but has been improved
with a ton of bug fixes and new features.
It now removes the useless imports from your component imports after the migration.
It also now has a new option &lt;code&gt;format&lt;/code&gt; to reformat your templates after the migration.
The option is &lt;code&gt;true&lt;/code&gt; by default, but can be turned off:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ng&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; g&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; @angular/core:control-flow&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; --path&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; src/app/app.component.html&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; --format=false&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;INFINITE_CHANGE_DETECTION&lt;/h2&gt;
&lt;p&gt;This is not a new feature, but this bug fix is worth mentioning.
Angular v17.1 fixes a bug for transplanted views, but this will also be useful for signals.&lt;/p&gt;
&lt;p&gt;The framework now runs change detection while there are still dirty
views to be refreshed in the tree.
If too many loops are detected, the framework will throw an error: &lt;code&gt;INFINITE_CHANGE_DETECTION&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This will remind the oldest Angular developers of the good old days of AngularJS,
when we had to be careful with infinite digest loops 👴.&lt;/p&gt;
&lt;p&gt;Angular v17.1 will throw this error if you have 100 loops in a row at the moment.&lt;/p&gt;
&lt;h2&gt;Angular CLI&lt;/h2&gt;
&lt;h3&gt;Vite v5&lt;/h3&gt;
&lt;p&gt;The Angular CLI v17.1 now uses Vite v5 under the hood.
Vite v5 was recently released,
you can read more about it in the &lt;a href=&quot;https://vitejs.dev/blog/announcing-vite5&quot;&gt;official blog post&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Application builder migration&lt;/h3&gt;
&lt;p&gt;If you haven&amp;#39;t migrated to the new application builder yet,
there is now a migration schematic to help you with that:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ng&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; update&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; @angular/cli&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; --name=use-application-builder&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Keyboard shortcuts in dev server&lt;/h3&gt;
&lt;p&gt;After running &lt;code&gt;ng serve&lt;/code&gt;, you can now see in the terminal the following line:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;Watch&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; mode&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; enabled.&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; Watching&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; file&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; changes...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;  ➜&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;  Local:&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;   http://localhost:4200/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;  ➜&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;  press&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; h&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; enter&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; show&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; help&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you press &amp;#39;h + enter&amp;#39;, you will see the list of available keyboard shortcuts:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;Shortcuts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;press&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; r&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; enter&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; force&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; reload&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; browser&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;press&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; u&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; enter&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; show&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; server&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; url&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;press&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; o&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; enter&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; open&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; browser&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;press&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; c&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; enter&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; clear&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; console&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;press&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; q&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; enter&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; quit&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Quite cool!&lt;/p&gt;
&lt;h3&gt;Running tests with Web Test Runner&lt;/h3&gt;
&lt;p&gt;An experimental builder is now available to run tests with
&lt;a href=&quot;https://modern-web.dev/docs/test-runner/overview/&quot;&gt;Web Test Runner&lt;/a&gt;.
It is &lt;em&gt;very&lt;/em&gt; early stage, but you can try it out by replacing the &lt;code&gt;karma&lt;/code&gt; builder with &lt;code&gt;web-test-runner&lt;/code&gt; in the &lt;code&gt;angular.json&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;builder&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;@angular-devkit/build-angular:web-test-runner&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You then need to install the &lt;code&gt;@web/test-runner&lt;/code&gt; package,
and here you go!
Running &lt;code&gt;ng test&lt;/code&gt; will now use Web Test Runner instead of Karma
(and bundle the files with the &lt;code&gt;application&lt;/code&gt; builder, which uses esbuild,
and not Webpack as the current &lt;code&gt;karma&lt;/code&gt; builder does).&lt;/p&gt;
&lt;p&gt;A lot of options aren&amp;#39;t available yet,
so you can&amp;#39;t change the browser for example (it only runs in Chrome for now),
or define reporters, or use any kind of configuration.&lt;/p&gt;
&lt;p&gt;In the future, we will be able to define a configuration file for Web Test Runner,
use other browsers (WTR supports using Playwright to download and run tests in other browsers), etc.&lt;/p&gt;
&lt;p&gt;This builder will probably be the default in the future,
as Karma is now deprecated.&lt;/p&gt;
&lt;h3&gt;loader option&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;application&lt;/code&gt; builder gained a new &lt;code&gt;loader&lt;/code&gt; option.
It allows defining the type of loader to use for a specified file extension.
The file matching the extension can then be used
within the application code via an import.&lt;/p&gt;
&lt;p&gt;The available loaders that can be used are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;text&lt;/code&gt; which treats the content as a string&lt;/li&gt;
&lt;li&gt;&lt;code&gt;binary&lt;/code&gt; which treats the content as a Uint8Array&lt;/li&gt;
&lt;li&gt;&lt;code&gt;file&lt;/code&gt; which emits the file and provides the runtime location of the file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;empty&lt;/code&gt; which considers the content to be empty and will not include it in bundles&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example, to inline the content of SVG files into the bundled application,
you can use the following configuration in the &lt;code&gt;angular.json&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;loader: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;.svg&quot;: &quot;text&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then an SVG file can be imported in your code with:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import content from &apos;./logo.svg&apos;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;TypeScript needs to be aware of the module type for the import to prevent type-checking
errors during the build, so you&amp;#39;ll need to add a type definition for the SVG file:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;declare module &quot;*.svg&quot; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const content: string;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  export default content;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Output location&lt;/h3&gt;
&lt;p&gt;It is now possible to customize the output location of the build artifacts:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;outputPath&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;base&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;dist/my-app&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;browser&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;server&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;node-server&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;media&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;resources&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Retain special CSS comments&lt;/h3&gt;
&lt;p&gt;By default, the CLI removes comments from CSS files during the build.
If you want to retain them because you use some tools that rely on them,
you can now set the &lt;code&gt;removeSpecialComments&lt;/code&gt; option to &lt;code&gt;false&lt;/code&gt; in the &lt;code&gt;optimization&lt;/code&gt; section of your &lt;code&gt;angular.json&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;optimization&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;styles&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;removeSpecialComments&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Allowed CommonJS dependencies&lt;/h3&gt;
&lt;p&gt;You can now specify &lt;code&gt;*&lt;/code&gt; as a package name in the &lt;code&gt;allowedCommonJsDependencies&lt;/code&gt; option to allow all packages in your build:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;allowedCommonJsDependencies&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;--no-browsers in tests&lt;/h3&gt;
&lt;p&gt;You can now use the &lt;code&gt;--no-browsers&lt;/code&gt; option when running tests with the CLI.
This will prevent the browser from opening when running tests,
which can be useful if you are inside a container for example.
This was already possible by setting the &lt;code&gt;browsers&lt;/code&gt; option to &lt;code&gt;[]&lt;/code&gt; in the &lt;code&gt;karma.conf.js&lt;/code&gt; file, but not from the CLI command.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;ng&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; test&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; --no-browsers&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;That&amp;#39;s all for this release, stay tuned!&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>What&apos;s new in Vue 3.4?</title>
    <link href="https://blog.ninja-squad.com/2023/12/29/what-is-new-vue-3.4"/>
    <updated>2023-12-29T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2023/12/29/what-is-new-vue-3.4</id>
    <content type="html">
      &lt;p&gt;&lt;a href=&quot;https://blog.vuejs.org/posts/vue-3-4&quot;&gt;Vue&amp;nbsp;3.4.0&lt;/a&gt; is here!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;a href=&quot;https://github.com/vuejs/core/blob/main/CHANGELOG.md#340-slam-dunk-2023-12-29&quot;&gt;
    &lt;img class=&quot;img-fluid&quot; style=&quot;max-width: 60%&quot; src=&quot;/assets/images/vue.webp&quot; alt=&quot;Vue logo&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;The last minor release was v3.3.0 in May.
Since then, we have seen a few patch releases,
some coming with new features.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s see what we have in this release!&lt;/p&gt;
&lt;h2&gt;v-bind shorthand syntax&lt;/h2&gt;
&lt;p&gt;It is now possible to use a shorthand syntax 
for &lt;code&gt;v-bind&lt;/code&gt; when the key and value have the same name!&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;&amp;#x3C;!-- before --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; v-bind&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;--&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; or&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; --&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;&amp;#x3C;div :id=&quot;id&quot;&gt;&amp;#x3C;/div&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;&amp;#x3C;!-- after --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;&amp;#x3C;div v-bind:id&gt;&amp;#x3C;/div&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;&amp;#x3C;-- or --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;&amp;#x3C;div :id&gt;&amp;#x3C;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Performances improvements for the reactivity system&lt;/h2&gt;
&lt;p&gt;Johnson Chu, the author of &lt;a href=&quot;https://github.com/vuejs/language-tools&quot;&gt;Volar&lt;/a&gt;,
has done massive work to improve the performance of the reactivity system.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s consider a scenario where you have a &lt;code&gt;computed&lt;/code&gt; A that depends on a &lt;code&gt;computed&lt;/code&gt; B.
In Vue v3.3, if B is re-evaluated, A is also re-evaluated, even if B has the same value as before.
In Vue v3.4, A is not re-evaluated if B has the same value as before.
This is also true for &lt;code&gt;watch&lt;/code&gt; functions.&lt;/p&gt;
&lt;p&gt;Other improvements have been made for Arrays mutations,
for watchers that depend on multiple computed values,
and more (as you can see in the &lt;a href=&quot;https://github.com/vuejs/core/pull/5912&quot;&gt;PR description&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;This should avoid a whole lot of unnecessary re-renders! 🚀
(and hopefully, don&amp;#39;t introduce any regression 🤞).&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;computed&lt;/code&gt; previous value&lt;/h2&gt;
&lt;p&gt;You can now get the previous value in a &lt;code&gt;computed&lt;/code&gt;,
as the first parameter of the getter function.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; count &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; double &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; computed&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;prev&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;prev&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;count&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;++;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// logs 0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can be useful if you want to manually compare object values.
(&lt;code&gt;computed&lt;/code&gt; internally uses &lt;code&gt;Object.is&lt;/code&gt; to compare the previous and current values,
which is not always what you want, see the &lt;a href=&quot;https://github.com/vuejs/core/pull/9497&quot;&gt;PR description&lt;/a&gt;).
This is especially useful with the new reactivity system improvements.
In v3.4, a computed property will only trigger effects when its computed value has changed from the previous one.
But in the case of a computed that return new objects, Vue thinks that the previous and current values are different.
If you want to avoid triggering effects in that case, you can compare the previous and current values manually.&lt;/p&gt;
&lt;h2&gt;Performances improvements for the compiler&lt;/h2&gt;
&lt;p&gt;The Vue compiler has been improved to be faster.
Evan rewrote the parser entirely, to avoid using regexes.
The code generation has also been improved.
They are now nearly 2 times faster!&lt;/p&gt;
&lt;p&gt;This should not have a huge impact on your build times,
as the Vue compiler is not the only step in the build process
(you usually have the TypeScript compiler, the CSS preprocessor, etc.).&lt;/p&gt;
&lt;h2&gt;Support for import attributes&lt;/h2&gt;
&lt;p&gt;It is now possible to use import attributes in SFC (both in JS and TS):&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; json &lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;./foo.json&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; with&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The support for &lt;code&gt;using&lt;/code&gt; has also been added (new feature for explicit resource management in JS, see the proposal &lt;a href=&quot;https://github.com/tc39/proposal-explicit-resource-management&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;h2&gt;watch &lt;code&gt;once&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;watch&lt;/code&gt; function gained a new option called &lt;code&gt;once&lt;/code&gt;.
When set to &lt;code&gt;true&lt;/code&gt;, the watcher is removed after the first call.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;watch&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;foo&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;foo changed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;},&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; once&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It was previously possible to achieve the same result by using the returned &lt;code&gt;stop&lt;/code&gt; function:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; stop &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; watch&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;foo&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;foo changed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  stop&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Props validation&lt;/h2&gt;
&lt;p&gt;As you probably know, Vue provides a mechanism to validate props.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;defineProps&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  min&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    type&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    validator&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; value &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  max&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    type&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    validator&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; value &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above example, the &lt;code&gt;min&lt;/code&gt; and &lt;code&gt;max&lt;/code&gt; props must be positive numbers.
In Vue v3.4, the &lt;code&gt;validator&lt;/code&gt; function is now called with a second argument
containing all the props, allowing to validate the value against other props.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;defineProps&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  min&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    type&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    validator&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; value &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  max&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    type&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    validator&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; props&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; value &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; props&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;min&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then if you try to use the component with &lt;code&gt;max&lt;/code&gt; being lower than &lt;code&gt;min&lt;/code&gt;,
you will get a warning.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Invalid prop: custom validator check failed for prop &quot;max&quot;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;SSR hydration mismatch warnings&lt;/h2&gt;
&lt;p&gt;When using SSR, the client-side hydration will now warn you with a message
that includes the mismatching element.
It was sometimes hard to find the mismatching element in the DOM,
as the warning was in v3.3:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[Vue warn]: Hydration completed but contains mismatches.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In v3.4, the warning now contains the actual element
(not only its tag name but the actual DOM element, so you can click on it),
allowing us to see where it is in the DOM and why it failed.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[Vue warn]: Hydration text content mismatch in &amp;#x3C;h2&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- Server rendered: Hello server&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- Client rendered: Hello client&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Vue now also warns you if you have a mismatch in classes, styles, or attributes!&lt;/p&gt;
&lt;p&gt;You can enable this feature in production as well by using a feature flag
in your Vite config called &lt;code&gt;__VUE_PROD_HYDRATION_MISMATCH_DETAILS__&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; defineConfig&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  plugins&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;vue&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  define&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    __VUE_PROD_HYDRATION_MISMATCH_DETAILS__&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;MathML support&lt;/h2&gt;
&lt;p&gt;It is now possible to write templates using MathML
(in addition to HTML and SVG)!&lt;/p&gt;
&lt;p&gt;The template below displays a beautiful &lt;code&gt;x²&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;math&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;mrow&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;msup&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;mi&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;mi&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;mn&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;mn&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;msup&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;mrow&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;math&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;defineModel&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;defineModel&lt;/code&gt; function was introduced as an experimental API in v3.3,
is now a stable API.
It is now the recommended way to define custom v-models.&lt;/p&gt;
&lt;p&gt;Compared to what we explained in our &lt;a href=&quot;/2023/05/15/what-is-new-vue-3.3&quot;&gt;previous blog post&lt;/a&gt;, the &lt;code&gt;local&lt;/code&gt; option has been removed (see &lt;a href=&quot;https://github.com/vuejs/rfcs/discussions/503#discussioncomment-7566278&quot;&gt;this discussion&lt;/a&gt; if you want to know why).
The model now automatically adapts based on whether the parent provides a &lt;code&gt;v-model&lt;/code&gt; or not.&lt;/p&gt;
&lt;p&gt;Another change it that it is now possible to handle modifiers.
For example, if you want to handle the &lt;code&gt;.number&lt;/code&gt; modifier, you can do:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;count&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; countModifiers&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; defineModel&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  set&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;countModifiers&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;?.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;      return&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; Number&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(countModifiers&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;?.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;number)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // true if the .number modifier is used&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can type the modifiers by using &lt;code&gt;defineModel&amp;lt;number, &amp;#39;number&amp;#39;&amp;gt;({ ... })&lt;/code&gt;.
The first type parameter is the type of the model value,
and the second one is the type of the modifiers (which can be a union type if you want to handle several ones).&lt;/p&gt;
&lt;p&gt;You can play with this &lt;a href=&quot;https://play.vuejs.org/#__DEV__eNqNU02P0zAQ/StWLu1Kjc2qnLrZsoD2ABILAm6EQ5pMWhfHtvyRrRTlvzN20pJ2KeLmmXmeefPxuuSt1rT1kKySzJaGa0csOK/XueSNVsaRjhioSU9qoxoyQ+jsFHqvGj36KQtGyDS7y2UuSyWtI2qzJ/fh/7wjpfLSrcgt6W9ymbGhGJZBw0GjReEALUKy3e266+LXvs8YWtEba7VpoyoQVPpmA+Y+TxBFY+I8IQyBGZvkShbJQDRtCk33VknssgvZ8jFg82RFoif4kHyw82TnnLYrxspK4jcsyFtDJTgmdcMeEMYMluQNpJVqHpb0NX2VmpIuWcWtm8Yo2CbdGPVswWCmPFlMajF0tmBSA7ICA+Z/a198e1H/Iv6CQ6DQ57LH8TiLe6r59mI4Jc6aCzCfteO4x7MhFUKo54/R54yHU0PlDspff/Hv7WFo7IuByGwyBFeYLeDqQvjx2xMc8H0K4qa9GBdyJfgVrBI+cBxg77yskPYEF9l+iLvmcvvdPh4cSHtsKhCN04j4uJRwZtda/0N3SZeTKR4vf6IhUcgtnmc4sJOeBkn8iOe6GOTwSVW85mDsT5RJBTWXgC4Q2XDgCzIbHrP1PLLAVPO2EB5ujqx4Tebnqd6M6jhBCArQeSPJU/SPCVClIYQtTBAxFCOhtYAJpJUAKtT2Wp07wlgcZSDjdkDGAMElRSjhlngL1b9lX/E2PvDJpfbuKHYc46jwAYdHHoDnSu9/AxtCnvc=&quot;&gt;demo&lt;/a&gt; to see how it works.&lt;/p&gt;
&lt;h2&gt;TypeScript improvements&lt;/h2&gt;
&lt;p&gt;An effort has been made to sanitize the types (which will be helpful for all libraries in the ecosystem).&lt;/p&gt;
&lt;p&gt;A notable improvement for developers is that &lt;code&gt;app.directive&lt;/code&gt;,
used to register global directives, can now be properly typed:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;directive&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;HTMLElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;custom&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  mounted&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;el&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; binding&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // el is correctly typed as HTMLElement&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // binding is correctly typed as string&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Deprecated features removed&lt;/h2&gt;
&lt;p&gt;The reactivity transform experiment has been removed.
It had been deprecated in v3.3.0 (see our &lt;a href=&quot;/2023/05/15/what-is-new-vue-3.3&quot;&gt;previous blog post&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Vnode hook events written like &lt;code&gt;vnodeMounted&lt;/code&gt; have been deprecated in v3.3
(see our &lt;a href=&quot;/2023/05/15/what-is-new-vue-3.3&quot;&gt;previous blog post&lt;/a&gt;)
and they are now no longer supported.
You should use the &lt;code&gt;@vue:&lt;/code&gt; syntax instead, like &lt;code&gt;@vue:mounted&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;v-is&lt;/code&gt; directive has also been removed.&lt;/p&gt;
&lt;h2&gt;News from the ecosystem&lt;/h2&gt;
&lt;h3&gt;Vue 2 End of Life&lt;/h3&gt;
&lt;p&gt;Vue 2 has reached its end of life, and Evan wrote a blog post about it:&lt;/p&gt;
&lt;p&gt;👉 &lt;a href=&quot;https://blog.vuejs.org/posts/vue-2-eol&quot;&gt;https://blog.vuejs.org/posts/vue-2-eol&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Vapor mode&lt;/h3&gt;
&lt;p&gt;Vapor (&lt;code&gt;@vue/vapor&lt;/code&gt;) is making progress with a &lt;a href=&quot;https://github.com/vuejs/core-vapor&quot;&gt;new repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For now, it introduces two work-in-progress packages: a new compiler and a new runtime.
They only support the most basic features at the moment,
and aren&amp;#39;t easily usable.
There is a playground in the repository if you want to try it out.&lt;/p&gt;
&lt;p&gt;The biggest difference with Vue 3 is that Vapor generates a rendering function that does not rely on virtual DOM.&lt;/p&gt;
&lt;p&gt;For example, the following component:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; setup&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; lang&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ts&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; computed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;vue/vapor&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; count &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; double &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; computed&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; inc &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;++&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;red&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Counter&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; count &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; * 2 = &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; double &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; @&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;click&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;inc&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;inc&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;generates the following render function:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; _sfc_render&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;_ctx&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; t0&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; _template&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;&amp;#x3C;div&gt;&amp;#x3C;h1 class=&quot;red&quot;&gt;Counter&amp;#x3C;/h1&gt;&amp;#x3C;div&gt; * 2 = &amp;#x3C;/div&gt;&amp;#x3C;button&gt;inc&amp;#x3C;/button&gt;&amp;#x3C;/div&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; n0&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; t0&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; [,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;n3&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;],&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;n4&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; _children&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;n0&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; n1&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; _createTextNode&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;_ctx&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;count&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; n2&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; _createTextNode&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;_ctx&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;double&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  _prepend&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;n3&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; n1&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  _append&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;n3&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; n2&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  _on&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;n4&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;click&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (...&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; _ctx&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;inc&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; _ctx&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;inc&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  _watchEffect&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    _setText&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;n1&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; _ctx&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;count&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  _watchEffect&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    _setText&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;n2&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; _ctx&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;double&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; n0&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see the render function is using a different strategy than Vue 3:
it creates the static elements, then it creates the dynamic elements,
and finally it updates the dynamic elements when needed using &lt;code&gt;watchEffect&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can check in the project&amp;#39;s README the features that are supported and the ones that are not.&lt;/p&gt;
&lt;h3&gt;Vue Test Utils&lt;/h3&gt;
&lt;p&gt;VTU should now have better type-checking support for TypeScript users.
For example &lt;code&gt;wrapper.setProps({ foo: &amp;#39;bar&amp;#39; })&lt;/code&gt; will now correctly error
if the component has no &lt;code&gt;foo&lt;/code&gt; prop.&lt;/p&gt;
&lt;h3&gt;create-vue&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;create-vue&lt;/code&gt; now generates projects using Vite v5,
which was &lt;a href=&quot;https://vitejs.dev/blog/announcing-vite5&quot;&gt;recently released&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Nuxt&lt;/h3&gt;
&lt;p&gt;Nuxt v3.9 is out as well, with the support of Vue 3.4.
It brings a lot of new features and experiments:
you can read more in the &lt;a href=&quot;https://nuxt.com/blog/v3-9&quot;&gt;official blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s all for this release. Stay tuned for the next one!&lt;/p&gt;
&lt;p&gt;Our &lt;a href=&quot;https://books.ninja-squad.com/vue&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://vue-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/vue&quot;&gt;training&lt;/a&gt; are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>What&apos;s new in Angular 17?</title>
    <link href="https://blog.ninja-squad.com/2023/11/09/what-is-new-angular-17.0"/>
    <updated>2023-11-09T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2023/11/09/what-is-new-angular-17.0</id>
    <content type="html">
      &lt;p&gt;Angular&amp;nbsp;v17 is here!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;a href=&quot;https://github.com/angular/angular/releases/tag/17.0.0&quot;&gt;
    &lt;img class=&quot;img-fluid&quot; style=&quot;max-width: 60%&quot; src=&quot;/assets/images/angular_gradient.webp&quot; alt=&quot;Angular logo&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;For French-speaking people, I talked about the release on the &lt;a href=&quot;https://www.youtube.com/live/YBty95aSP6c?si=E_n8L59HC5P1NUxe&quot;&gt;Angular Devs France YouTube channel&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is a major release packed with features: let&amp;#39;s dive in!&lt;/p&gt;
&lt;h2&gt;angular.dev&lt;/h2&gt;
&lt;p&gt;The Angular team has been cranking it communication-wise lately,
with a &lt;a href=&quot;https://www.youtube.com/watch?v=Wq6GpTZ7AX0&quot;&gt;live event&lt;/a&gt;
to unveil the new features of Angular v17,
and a new website called &lt;a href=&quot;https://angular.dev&quot;&gt;angular.dev&lt;/a&gt;,
which will be the future official website.
It features the same documentation but with a new interactive tutorial,
and a playground to try Angular without installing anything
(as Vue or Svelte do as well).&lt;/p&gt;
&lt;p&gt;Angular also has a new logo that you can see at the top of this post!&lt;/p&gt;
&lt;h2&gt;Control flow syntax&lt;/h2&gt;
&lt;p&gt;Even if it is only a &amp;quot;developer preview&amp;quot; feature, this is a big one!
Angular templates are evolving to use a new syntax for control flow structures.&lt;/p&gt;
&lt;p&gt;We wrote a dedicated blog post about this feature: &lt;/p&gt;
&lt;p&gt;👉 &lt;a href=&quot;/2023/10/11/angular-control-flow-syntax/&quot;&gt;Angular Control Flow Syntax&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An experimental migration allows you to give it a try in your project.
The syntax should become stable in v18, and be the recommended way to write templates at that point.&lt;/p&gt;
&lt;h2&gt;Deferrable views&lt;/h2&gt;
&lt;p&gt;Another big feature is the introduction of deferrable views using &lt;code&gt;@defer&lt;/code&gt; in templates.&lt;/p&gt;
&lt;p&gt;We wrote a dedicated blog post about this feature:&lt;/p&gt;
&lt;p&gt;👉 &lt;a href=&quot;/2023/11/02/angular-defer/&quot;&gt;Angular Deferrable Views&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is a &amp;quot;developer preview&amp;quot; feature as well and should become stable in v18.
It&amp;#39;s probably going to be less impactful than the control flow syntax,
but it&amp;#39;s still interesting to have a way to easily lazy-load parts of a template.&lt;/p&gt;
&lt;h2&gt;Signals are now stable!&lt;/h2&gt;
&lt;p&gt;The Signals API is now marked as stable 🎉.
Except &lt;code&gt;effect()&lt;/code&gt;, and the RxJS interoperability functions &lt;code&gt;toSignal&lt;/code&gt; and &lt;code&gt;toObservable&lt;/code&gt;
which might change and are still marked as &amp;quot;developer preview&amp;quot;.&lt;/p&gt;
&lt;p&gt;The API has not changed much since our &lt;a href=&quot;/2023/04/26/angular-signals/&quot;&gt;blog post about Signals&lt;/a&gt;, 
but some notable things happened.&lt;/p&gt;
&lt;h3&gt;mutate has been dropped&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;mutate()&lt;/code&gt; has been dropped from the API.
You were previously able to write something like:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;mutate&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;usersArray&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; usersArray&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(newUser))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And you&amp;#39;ll now have to write:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;update&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;usersArray&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;usersArray&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; newUser])&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;mutate()&lt;/code&gt; method was introducing some issues with other libraries,
and was not worth the trouble as it can be replaced by &lt;code&gt;update()&lt;/code&gt; quite easily.&lt;/p&gt;
&lt;h2&gt;template diagnostic&lt;/h2&gt;
&lt;p&gt;A new compiler diagnostic is available to help you spot missing signal invocations in your templates.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s say you have a &lt;code&gt;count&lt;/code&gt; signal used in a template, but forgot the &lt;code&gt;()&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; count &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;throws with:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;NG8109: count is a function and should be invoked: count()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;flushEffects&lt;/h3&gt;
&lt;p&gt;A new method is available (as a developer preview) 
on the &lt;code&gt;TestBed&lt;/code&gt; class to trigger pending effects: &lt;code&gt;flushEffects&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;TestBed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;flushEffects&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is because effect timing has changed a bit:
they are no longer triggered by change detection but scheduled via the microtask queue
(like &lt;code&gt;setTimeout()&lt;/code&gt; or &lt;code&gt;Promise.resolve()&lt;/code&gt;).
So while you could previously trigger them by calling &lt;code&gt;detectChanges()&lt;/code&gt; on the fixture,
you now have to call &lt;code&gt;TestBed.flushEffects()&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;afterRender and afterNextRender phases&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;afterRender&lt;/code&gt; and &lt;code&gt;afterNextRender&lt;/code&gt; functions introduced in Angular v16.2
can now specify a &lt;code&gt;phase&lt;/code&gt; option.
Angular uses this phase to schedule callbacks to improve performance.
There are 4 possible values, and they run in the following order:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;EarlyRead&lt;/code&gt; (when you need to read the DOM before writing to the DOM)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Write&lt;/code&gt; (needed if you want to write to the DOM, for example, to initialize a chart using a third-party library)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MixedReadWrite&lt;/code&gt; (default, but should be avoided if possible to use a more specific phase)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Read&lt;/code&gt; (recommended if you only need to read the DOM)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I &lt;em&gt;think&lt;/em&gt; we should be able to use &lt;code&gt;Read&lt;/code&gt; and &lt;code&gt;Write&lt;/code&gt; in most cases.
&lt;code&gt;EarlyRead&lt;/code&gt; and &lt;code&gt;MixedReadWrite&lt;/code&gt; degrade performances, so they should be avoided if possible.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ChartComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  @&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;ViewChild&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;canvas&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;canvas&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;!:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ElementRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;HTMLCanvasElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  constructor&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    afterNextRender&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;      const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; ctx&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;canvas&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;nativeElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      new&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; Chart&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;ctx&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;line&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; data&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    },&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; phase&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; AfterRenderPhase&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Write&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Performances&lt;/h3&gt;
&lt;p&gt;The internal algorithm changed to use a ref-counting mechanism instead of a mechanism based on bi-directional weak references. It should be more performant than it was in many cases.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s also worth noting that the change detection algorithm has been improved to be more efficient when using Signals.
Previously, when reading a signal in a template, Angular was marking the component
and all its ancestors as dirty when the signal was updated
(as it currently does with when &lt;code&gt;OnPush&lt;/code&gt; components are marked for check).
It&amp;#39;s now a bit smarter and only marks the component as dirty when the signal is updated and not all its ancestors.
It will still check the whole application tree,
but the algorithm will be faster because some components will be skipped.&lt;/p&gt;
&lt;p&gt;We don&amp;#39;t have a way to write pure signal-based components yet, with no need for ZoneJS,
but it should be coming eventually!&lt;/p&gt;
&lt;h2&gt;styleUrls as a string&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;styleUrls&lt;/code&gt; and &lt;code&gt;styles&lt;/code&gt; properties of the &lt;code&gt;@Component&lt;/code&gt; decorator can now be a string instead of an array of strings.
A new property called &lt;code&gt;styleUrl&lt;/code&gt; has also been introduced.&lt;/p&gt;
&lt;p&gt;You can now write:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  selector&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;app-root&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  templateUrl&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;./app.component.html&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  styleUrl&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;./app.component.css&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; AppComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;View Transitions router support&lt;/h2&gt;
&lt;p&gt;The View Transitions API is a fairly new browser API
that allows you to animate the transition between two views.
It is only supported in recent versions of Chrome, Edge, and Opera (see 
&lt;a href=&quot;https://caniuse.com/mdn-api_document_startviewtransition&quot;&gt;caniuse.com stats&lt;/a&gt;)
but not in Firefox yet.
It works by taking a screenshot of the current view and animating it to the new view.&lt;/p&gt;
&lt;p&gt;I&amp;#39;m not very familiar with this API,
but there is a great article about it on
&lt;a href=&quot;https://developer.chrome.com/docs/web-platform/view-transitions/&quot;&gt;developer.chrome.com&lt;/a&gt;
and cool demos on &lt;a href=&quot;https://http203-playlist.netlify.app/&quot;&gt;this site&lt;/a&gt; (open it with a browser that supports this API of course).&lt;/p&gt;
&lt;p&gt;Angular v17 adds support for this API in the router.
This is an experimental feature, and you&amp;#39;ll have to enable it by using &lt;code&gt;withTransitionViews()&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;bootstrapApplication&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(AppComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  providers&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; provideRouter&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;routes&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; withTransitionViews&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;] &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By default, you get a nice fade-in/fade-out transition between views when navigating from one route to another.
You can customize the animation using CSS, animate the whole view or skip part of it,
or indicate which DOM elements are in fact the same entities in the old and new views:
the browser will then do its best to animate between the states.&lt;/p&gt;
&lt;p&gt;It is possible to skip the initial transition by using the &lt;code&gt;skipInitialTransition&lt;/code&gt; option:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;bootstrapApplication&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(AppComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  providers&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; provideRouter&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;routes&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; withTransitionViews&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; skipInitialTransition&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; })&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;] &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;More advanced scenarios require to add/remove CSS classes to the views,
so the router also lets you run an arbitrary function when the transition is done
if you use the &lt;code&gt;onViewTransitionCreated&lt;/code&gt; option to define a callback.&lt;/p&gt;
&lt;h2&gt;Http&lt;/h2&gt;
&lt;p&gt;The fetch backend (introduced in &lt;a href=&quot;/2023/06/14/what-is-new-angular-16.1&quot;&gt;Angular v16.1&lt;/a&gt;)
has been promoted to stable.&lt;/p&gt;
&lt;p&gt;When using SSR, it is now possible to customize the transfer cache, using &lt;code&gt;withHttpTransferCacheOptions(options)&lt;/code&gt;.
The options can be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;filter&lt;/code&gt;: a function to filter the requests that should be cached&lt;/li&gt;
&lt;li&gt;&lt;code&gt;includeHeaders&lt;/code&gt;: the list of headers to include (none by default)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;includePostRequests&lt;/code&gt;: whether or not to cache POST requests (by default only GET and HEAD requests are cached)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;bootstrapApplication&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(AppComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  providers&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;provideHttpClient&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    withHttpTransferCacheOptions&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;({&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; includePostRequests&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Devtools&lt;/h2&gt;
&lt;p&gt;The devtools received some love as well,
and they now allow you to inspect the dependency injection tree.&lt;/p&gt;
&lt;h2&gt;Animations&lt;/h2&gt;
&lt;p&gt;No new feature for this part of Angular,
but it is now possible to lazy-load the animations package.
In a standalone application, you can use &lt;code&gt;provideAnimationsAsync()&lt;/code&gt; instead of
using &lt;code&gt;provideAnimations()&lt;/code&gt; and the necessary code for animations will be loaded asynchronously.&lt;/p&gt;
&lt;p&gt;The application should work the same,
but you should see an extra chunk appear when building the application.
That&amp;#39;s a few kilobytes of JavaScript that you don&amp;#39;t have to load upfront 🚀.&lt;/p&gt;
&lt;p&gt;You can disable animations by providing &lt;code&gt;&amp;#39;noop&amp;#39;&lt;/code&gt; as the value of &lt;code&gt;provideAnimationsAsync()&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;bootstrapApplication&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(AppComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  providers&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;provideAnimationsAsync&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;noop&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)] &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Performances&lt;/h2&gt;
&lt;p&gt;In dev mode, you&amp;#39;ll now get a warning if you load an oversized image
or if an image is the &amp;quot;Largest Contentful Paint element&amp;quot; in the page and is lazy-loaded 
(which is a bad idea, see &lt;a href=&quot;https://angular.io/errors/NG0913#lazy-loaded-lcp-element&quot;&gt;the explanations here&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;An image with src image.png has intrinsic file dimensions much larger than its &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;rendered size. This can negatively impact application loading performance. &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;For more information about addressing or disabling this warning, see  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;https://angular.io/errors/NG0913&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can configure this behavior via dependency injection,
for example, if you want to turn off these warnings:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;  provide&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; IMAGE_CONFIG&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; useValue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;    disableImageSizeWarning&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;    disableImageLazyLoadWarning&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;TypeScript 5.2 and Node.js v18&lt;/h2&gt;
&lt;p&gt;It&amp;#39;s worth noting that Angular now requires TypeScript 5.2 and Node.js v18.
Support for older versions has been dropped.&lt;/p&gt;
&lt;h2&gt;Angular CLI&lt;/h2&gt;
&lt;p&gt;A lot happened in the CLI!&lt;/p&gt;
&lt;p&gt;👉 Check out our &lt;a href=&quot;/2023/11/09/angular-cli-17.0/&quot;&gt;dedicated blog post about the CLI v17&lt;/a&gt; for more details.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;That&amp;#39;s all for this release, stay tuned!&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>What&apos;s new in Angular CLI 17.0?</title>
    <link href="https://blog.ninja-squad.com/2023/11/09/angular-cli-17.0"/>
    <updated>2023-11-09T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2023/11/09/angular-cli-17.0</id>
    <content type="html">
      &lt;p&gt;&lt;a href=&quot;https://github.com/angular/angular-cli/releases/tag/17.0.0&quot;&gt;Angular CLI 17.0.0&lt;/a&gt; is out!✨&lt;/p&gt;
&lt;p&gt;If you want to upgrade to 17.0.0 without pain (or to any other version, by the way), I have created a Github project to help: &lt;a href=&quot;https://github.com/cexbrayat/angular-cli-diff&quot;&gt;angular-cli-diff&lt;/a&gt;. Choose the version you&amp;#39;re currently using (16.2.0 for example), and the target version (17.0.0 for example), and it gives you a diff of all files created by the CLI: &lt;a href=&quot;https://github.com/cexbrayat/angular-cli-diff/compare/16.2.0...17.0.0&quot;&gt;angular-cli-diff/compare/16.2.0...17.0.0&lt;/a&gt;.
It can be a great help along with the official &lt;code&gt;ng update @angular/core @angular/cli&lt;/code&gt; command.
You have no excuse for staying behind anymore!&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s see what we&amp;#39;ve got in this release.&lt;/p&gt;
&lt;h2&gt;Standalone applications with Vite by default!&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;--standalone&lt;/code&gt; flag is now the default behavior of the CLI.
This means generating a new project with &lt;code&gt;ng new&lt;/code&gt; now uses standalone components by default,
and that the &lt;code&gt;ng generate component/pipe/directive&lt;/code&gt; command now generates standalone components/pipes/directives.&lt;/p&gt;
&lt;p&gt;Another notable change to &lt;code&gt;ng new&lt;/code&gt; is that the routing is now enabled by default.&lt;/p&gt;
&lt;p&gt;But the most important change is that the CLI now uses &lt;a href=&quot;https://vitejs.dev/&quot;&gt;Vite&lt;/a&gt; out-of-the-box!
A new builder called &lt;code&gt;application&lt;/code&gt; has been introduced, and is used when generating a new project.
This builder has a very similar configuration to the &lt;code&gt;browser&lt;/code&gt; builder,
so the migration is quite easy if you want to use Vite in an existing project
You have to change the builder from &lt;code&gt;browser&lt;/code&gt; to &lt;code&gt;application&lt;/code&gt; in the &lt;code&gt;angular.json&lt;/code&gt; file,
rename the &lt;code&gt;main&lt;/code&gt; property to &lt;code&gt;browser&lt;/code&gt;,
and remove a few options from the development configuration (&lt;code&gt;buildOptimizer&lt;/code&gt;, &lt;code&gt;vendorChunk&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Once migrated, the &lt;code&gt;ng serve&lt;/code&gt; command will use Vite instead of Webpack.
Build time should be faster, especially for cold starts (I saw 2-3x times improvement on my machine).
There is no HMR by default yet, but the global style changes are detected and applied automatically without reloading the page.&lt;/p&gt;
&lt;p&gt;Note that the output of the &lt;code&gt;ng build&lt;/code&gt; Vite-based command is now in &lt;code&gt;dist/my-project/browser&lt;/code&gt; instead of &lt;code&gt;dist/my-project&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;browser-esbuilder&lt;/code&gt; builder still exists, but will be removed in the future.
You should use the &lt;code&gt;application&lt;/code&gt; builder instead.&lt;/p&gt;
&lt;h2&gt;ng new --ssr&lt;/h2&gt;
&lt;p&gt;A new flag &lt;code&gt;--ssr&lt;/code&gt; has been added to the &lt;code&gt;ng new&lt;/code&gt; command to generate a new project
with SSR enabled out of the box.&lt;/p&gt;
&lt;p&gt;It generates a project similar to what you usually get and then runs the &lt;code&gt;@angular/ssr&lt;/code&gt; schematics
(you can also use the schematics directly on an existing project with &lt;code&gt;ng add @angular/ssr&lt;/code&gt;).
&lt;code&gt;@angular/ssr&lt;/code&gt; is a new package and replaces the Angular Universal package.
If you were using the Angular Universal package, &lt;code&gt;ng update&lt;/code&gt; migrates your configuration to use &lt;code&gt;@angular/ssr&lt;/code&gt; automatically.&lt;/p&gt;
&lt;p&gt;This schematic does the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;adds the &lt;code&gt;@angular/ssr&lt;/code&gt; package&lt;/li&gt;
&lt;li&gt;adds the &lt;code&gt;@angular/platform-server&lt;/code&gt; package&lt;/li&gt;
&lt;li&gt;adds the &lt;code&gt;express&lt;/code&gt; and &lt;code&gt;@types/express&lt;/code&gt; packages&lt;/li&gt;
&lt;li&gt;adds the &lt;code&gt;main.server.ts&lt;/code&gt; file (entry point for the application when running on the server)&lt;/li&gt;
&lt;li&gt;adds the &lt;code&gt;app.config.server.ts&lt;/code&gt; file (providers for the application when running on the server)&lt;/li&gt;
&lt;li&gt;adds the &lt;code&gt;tsconfig.server.json&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;adds the &lt;code&gt;server.ts&lt;/code&gt; file (the Express server, responsible for serving the application)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It updates the &lt;code&gt;angular.json&lt;/code&gt; configuration to add the following options to the &lt;code&gt;build&lt;/code&gt; target:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;server&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;src/main.server.ts&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;prerender&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ssr&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;entry&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;server.ts&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and adds the &lt;code&gt;provideClientHydration()&lt;/code&gt; to the (browser) application providers,
to have a smooth transition between the server and the client.
This is a new feature of Angular v16, and we talked about it in our article about the &lt;a href=&quot;/2023/05/03/what-is-new-angular-16.0&quot;&gt;v16 release&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When running &lt;code&gt;ng build&lt;/code&gt;, the CLI will now build the server bundle (in &lt;code&gt;dist/my-project/server&lt;/code&gt;) and the client bundle (in &lt;code&gt;dist/my-project/browser&lt;/code&gt;).
You can then run the generated server with:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;node dist/my-project/server/main.server.mjs&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This starts an Express server on port 4000 by default, which serves the rendered pages.&lt;/p&gt;
&lt;p&gt;The rendered pages are in the &lt;code&gt;browser&lt;/code&gt; folder, and are named &lt;code&gt;${page}/index.html&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dist/my-project/browser/index.html&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dist/my-project/browser/login/index.html&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dist/my-project/browser/register/index.html&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you use &lt;code&gt;localize&lt;/code&gt; in your application, the CLI will also build the localized bundles (in &lt;code&gt;dist/my-project/server/${lang}&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The prerendering mechanism should be quite accurate now,
as it uses the Angular router under the hood to navigate to each route and render it
(routes with parameters or redirections are skipped).
When prerendering is enabled, the CLI generates a &lt;code&gt;prerendered-routes.json&lt;/code&gt; file
that contains all the prerendered routes.
This is useful if you deploy on the cloud as this file is usually recognized by providers
to serve these files as static.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;routes&quot;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;/&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;/login&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;/register&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can disable the auto-discovery of routes by setting the &lt;code&gt;discoverRoutes&lt;/code&gt; option to &lt;code&gt;false&lt;/code&gt; in the &lt;code&gt;angular.json&lt;/code&gt; file. You can also provide your own list of routes in this file by defining &lt;code&gt;routeFiles&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;ssr&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;discoverRoutes&quot;: false,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;routeFiles&quot;: &quot;ssg-routes.txt&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This file must contain a list of routes that you want to render (and can contain parameterized routes).&lt;/p&gt;
&lt;p&gt;When running &lt;code&gt;ng serve&lt;/code&gt;, the CLI serves the application via Vite,
and only pre-renders the requested page (the one you&amp;#39;re currently on).&lt;/p&gt;
&lt;p&gt;You can also use a new option to &lt;code&gt;CommonEngine&lt;/code&gt; called &lt;code&gt;enablePerformanceProfiler&lt;/code&gt; to trace the performance of each step of the rendering:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const commonEngine = new CommonEngine({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  enablePerformanceProfiler: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When using SSR, it is recommended to use the Fetch version of the HTTP client,
by using &lt;code&gt;provideHttpClient(withFetch())&lt;/code&gt;
(as introduced in &lt;a href=&quot;/2023/06/14/what-is-new-angular-16.1&quot;&gt;Angular v16.1&lt;/a&gt;).
This is for performance and compatibility reasons.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;NG02801: Angular detected that `HttpClient` is not configured to use `fetch` APIs. It&apos;s strongly recommended to enable `fetch` for applications that use Server-Side Rendering for better performance and compatibility. To enable `fetch`, add the `withFetch()` to the `provideHttpClient()` call at the root of the application.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Functional HTTP interceptors by default&lt;/h2&gt;
&lt;p&gt;The CLI now generates functional interceptors by default,
without the need to specify &lt;code&gt;--functional&lt;/code&gt; anymore.
Class-based interceptors are still available with the &lt;code&gt;--no-functional&lt;/code&gt; option,
but you&amp;#39;re now encouraged to use the functional ones.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;That&amp;#39;s all for the CLI v17.0 release!
You&amp;#39;ll find more interesting features in our article about the
&lt;a href=&quot;/2023/11/09/what-is-new-angular-17.0&quot;&gt;framework v17.0.0 release&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>A guide to Angular Deferrable Views with @defer</title>
    <link href="https://blog.ninja-squad.com/2023/11/02/angular-defer"/>
    <updated>2023-11-02T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2023/11/02/angular-defer</id>
    <content type="html">
      &lt;p&gt;With the introduction of the &lt;a href=&quot;/2023/10/11/angular-control-flow-syntax&quot;&gt;Control flow syntax&lt;/a&gt;,
the Angular team has also introduced a new way to load components lazily
(as a developer preview for now).
We already have lazy-loading in Angular, but it is mainly based on the router.&lt;/p&gt;
&lt;p&gt;Angular v17 adds a new way to load components lazily, using the &lt;code&gt;@defer&lt;/code&gt; syntax in your templates.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;@defer&lt;/code&gt; lets you define a block of template that will be loaded lazily when a condition is met
(with all the components, pipes, directives, and libraries used in this block lazily loaded as well).
Several conditions can be used.
For example, it can be &amp;quot;as soon as possible (no condition)&amp;quot;,
&amp;quot;when the user scrolls to that section&amp;quot;,
&amp;quot;when the user clicks on that button&amp;quot; or &amp;quot;after 2 seconds&amp;quot;.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s say your home page displays a &amp;quot;heavy&amp;quot; &lt;code&gt;ChartComponent&lt;/code&gt; that uses a charting library
and some other dependencies, like a &lt;code&gt;FromNow&lt;/code&gt; pipe:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  selector&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ns-chart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  standalone&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  imports&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [FromNowPipe]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ChartComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // uses chart.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This component is used in the home page:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; ChartComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;./chart.component&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  selector&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ns-home&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; `&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    &amp;#x3C;!-- some content --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-chart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;  `&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  standalone&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  imports&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [ChartComponent]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; HomeComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the application is packaged, the &lt;code&gt;ChartComponent&lt;/code&gt; will be included in the main bundle:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;+------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;| main-xxxx.js  -  300KB |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;+------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;| home.component.ts      |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;| chart.component.ts     |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;| from-now.pipe.ts       |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;| chart.js               |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;+------------------------+&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s say that the component is not visible at first on the home page,
maybe because it is at the bottom of the page, or because it is in a tab that is not active.
It makes sense to avoid loading this component eagerly
because it would slow down the initial loading of the page.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;@defer&lt;/code&gt;, you can load this component only when the user really needs it.
Just wrapping the &lt;code&gt;ChartComponent&lt;/code&gt; in a &lt;code&gt;@defer&lt;/code&gt; block will do the trick:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; ChartComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;./chart.component&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  selector&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ns-home&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; `&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    &amp;#x3C;!-- some content --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    @defer&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (when isVisible) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-chart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;  `&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  standalone&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  imports&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [ChartComponent]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Angular compiler will rewrite the static import of the &lt;code&gt;ChartComponent&lt;/code&gt;
to a dynamic import (&lt;code&gt;() =&amp;gt; import(&amp;#39;./chart.component&amp;#39;)&lt;/code&gt;),
and the component will be loaded only when the condition is met.
As the component is now imported dynamically,
it will not be included in the main bundle.
The bundler will create a new chunk for it:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;+------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;| main-xxxx.js  -  100KB |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;+------------------------+       +-------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;| home.component.ts      |------&gt;| chunk-xxxx.js - 200KB   |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;+------------------------+       +-------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                 | chart.component.ts      |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                 | from-now.pipe.ts        |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                 | chart.js                |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                 +-------------------------+&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;chunk-xxxx.js&lt;/code&gt; file will only be loaded when the condition is met,
and the &lt;code&gt;ChartComponent&lt;/code&gt; will be displayed.&lt;/p&gt;
&lt;p&gt;Before talking about the various kinds of conditions that can be used with &lt;code&gt;@defer&lt;/code&gt;,
let&amp;#39;s see how to use another interesting feature:
displaying a placeholder until the deferred block is loaded.&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;@placeholder&lt;/code&gt;, &lt;code&gt;@loading&lt;/code&gt;, and &lt;code&gt;@error&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;You can define a placeholder template with &lt;code&gt;@placeholder&lt;/code&gt;
that will be displayed until the loading condition is met.
Then, while the block is loading, you can display a loading template with &lt;code&gt;@loading&lt;/code&gt;.
If no &lt;code&gt;@loading&lt;/code&gt; block is defined, the placeholder stays there until the block is loaded.
You can also define an error template with &lt;code&gt;@error&lt;/code&gt; that will be displayed if the block fails to load.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@defer&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (when show) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-chart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@placeholder&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Something until the loading starts&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@loading&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Loading...&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@error&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Something went wrong&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When using server-side rendering,
only the placeholder will be rendered on the server (the defer conditions will never trigger).&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;after&lt;/code&gt; and &lt;code&gt;minimum&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;As the &lt;code&gt;@defer&lt;/code&gt; block loading can be quite fast,
there is a risk that the loading block is displayed and hidden too quickly,
causing a &amp;quot;flickering&amp;quot; effect.&lt;/p&gt;
&lt;p&gt;To avoid this, you can use the &lt;code&gt;after&lt;/code&gt; option to specify after how many milliseconds
the loading should be displayed.&lt;/p&gt;
&lt;p&gt;If the block takes less than this delay to load, then the &lt;code&gt;@loading&lt;/code&gt; block is never displayed.&lt;/p&gt;
&lt;p&gt;You can also use the &lt;code&gt;minimum&lt;/code&gt; option to specify a minimum duration for the loading.
If the loading is faster than the minimum duration,
then the loading will be displayed for the minimum duration (this only applies if the loading is ever displayed).&lt;/p&gt;
&lt;p&gt;You can of course combine all these options:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@defer&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (when show) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-chart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@placeholder&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Something until the loading starts&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@loading&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (after 500ms&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; minimum 500ms) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Loading...&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also specify a &lt;code&gt;minimum&lt;/code&gt; duration for the placeholder.
It can be useful when the loading condition is immediate (for example, when no condition is specified).
In that case, the placeholder will be displayed for the minimum duration,
even if the block is loaded immediately,
to avoid a &amp;quot;flickering&amp;quot; effect.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@defer&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (when show) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-chart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@placeholder&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (minimum 500ms) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Something until the loading starts&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@loading&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (after 500ms&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; minimum 500ms) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Loading...&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conditions&lt;/h2&gt;
&lt;p&gt;Several conditions can be used with &lt;code&gt;@defer&lt;/code&gt;,
let&amp;#39;s see them one by one.&lt;/p&gt;
&lt;h3&gt;No condition or &lt;code&gt;on idle&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The simplest condition is to not specify any condition at all:
in this case, the block will be loaded when the browser is idle
(the loading is scheduled using &lt;code&gt;requestIdleCallback&lt;/code&gt;).&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@defer&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-chart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is equivalent to using the &lt;code&gt;on idle&lt;/code&gt; condition:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@defer&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (on idle) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-chart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Simple boolean condition with &lt;code&gt;when&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;You can also use a boolean condition to load a block of the template with &lt;code&gt;when&lt;/code&gt;.
Here, we display the defer block only when the &lt;code&gt;show&lt;/code&gt; property of the component is true:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@defer&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (when show) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-chart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that this is not the same as using &lt;code&gt;*ngIf&lt;/code&gt; on the block,
as the block will not be removed even if the condition becomes false later.&lt;/p&gt;
&lt;h3&gt;on &lt;code&gt;immediate&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;on immediate&lt;/code&gt; condition triggers the loading of the block immediately.
It does not display a placeholder, even if one is defined.&lt;/p&gt;
&lt;h3&gt;on &lt;code&gt;timer&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;on timer&lt;/code&gt; condition triggers the loading of the block after a given duration,
using &lt;code&gt;setTimeout&lt;/code&gt; under the hood.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@defer&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (on &lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;timer&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(2s)) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-chart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;on &lt;code&gt;hover&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Other conditions are based on user interactions.
These conditions can specify the element of the interaction using a template reference variable,
or none to use the placeholder element.
In the latter case, the placeholder element must exist
and have a single child element that will be used as the element of the interaction.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;on hover&lt;/code&gt; condition triggers the loading of the block when the user hovers the element.
Under the hood, it listens to the &lt;code&gt;mouseenter&lt;/code&gt; and &lt;code&gt;focusin&lt;/code&gt; events.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; #trigger&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Hover me&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@defer&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (on &lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;hover&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(trigger)) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-chart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or using the placeholder element:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@defer&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (on hover) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-chart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@placeholder&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Hover me&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;on &lt;code&gt;interaction&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;on interaction&lt;/code&gt; condition triggers the loading of the block when the user interacts with the element.
Under the hood, it listens to the &lt;code&gt;click&lt;/code&gt; and &lt;code&gt;keydown&lt;/code&gt; events.&lt;/p&gt;
&lt;h3&gt;on &lt;code&gt;viewport&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;on viewport&lt;/code&gt; condition triggers the loading of the block when the element becomes visible in the viewport.
Under the hood, it uses an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API&quot;&gt;intersection observer&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Multiple conditions&lt;/h3&gt;
&lt;p&gt;You can also combine multiple conditions using a comma-separated list:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;&amp;#x3C;!-- Loads if the user hovers the placeholder, or after 1 minute --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@defer&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (on hover&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; timer&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(60s)) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-chart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@placeholder&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Something until the loading starts&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Prefetching&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;@defer&lt;/code&gt; allows you
to separate the loading of a component from its display.
You can use the same conditions we previously saw to load a component using &lt;code&gt;prefetch&lt;/code&gt;,
and then display it with another condition.&lt;/p&gt;
&lt;p&gt;For example, you can prefetch the lazy-loaded content &lt;code&gt;on idle&lt;/code&gt;
and then display it &lt;code&gt;on interaction&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@defer&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (on interaction&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; prefetch on idle) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ns-chart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@placeholder&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Show me&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that the &lt;code&gt;@loading&lt;/code&gt; block will not be displayed if the deferred block is already prefetched
when the loading condition is met.&lt;/p&gt;
&lt;h2&gt;How to test deferred loading?&lt;/h2&gt;
&lt;p&gt;When a component uses defer blocks in its template,
you&amp;#39;ll have to do some extra work to test it.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;TestBed&lt;/code&gt; API has been extended to help you with that.
The &lt;code&gt;configureTestingModule&lt;/code&gt; method now accepts a &lt;code&gt;deferBlockBehavior&lt;/code&gt; option.
By default, this option is set to &lt;code&gt;DeferBlockBehavior.Manual&lt;/code&gt;,
which means that you&amp;#39;ll have to manually trigger the display of the defer blocks.
But let&amp;#39;s start with the other option instead.&lt;/p&gt;
&lt;p&gt;You can change this behavior by using &lt;code&gt;DeferBlockBehavior.Playthrough&lt;/code&gt;.
Playthrough means that the defer blocks will be displayed automatically
when a condition is met, as they would when the application runs in the browser.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;beforeEach&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  TestBed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;configureTestingModule&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    deferBlockBehavior&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; DeferBlockBehavior&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Playthrough&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In that case, the defer blocks will be displayed automatically when a condition is met,
after calling &lt;code&gt;await fixture.whenStable()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So if we test a component with a deferred block that is visible after clicking on a button,
we can use:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// Click the button to trigger the deferred block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;fixture&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;nativeElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;querySelector&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;click&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;fixture&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;detectChanges&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// Wait for the deferred block to render&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; fixture&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;whenStable&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// Check its content&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; loadedBlock &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; fixture&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;nativeElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;querySelector&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;expect&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(loadedBlock&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;textContent)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;toContain&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Some lazy-loaded content&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you want to use the &lt;code&gt;DeferBlockBehavior.Manual&lt;/code&gt; behavior,
you&amp;#39;ll have to manually trigger the display of the defer blocks.
To do so, the fixture returned by &lt;code&gt;TestBed.createComponent&lt;/code&gt; now has an async &lt;code&gt;getDeferBlocks&lt;/code&gt; method
that returns an array of &lt;code&gt;DeferBlockFixture&lt;/code&gt; objects.
Each of these fixtures has a &lt;code&gt;render&lt;/code&gt; method that you can call to display the block
in a specific state, by providing a &lt;code&gt;DeferBlockState&lt;/code&gt; parameter.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;DeferBlockState&lt;/code&gt; is an enum with the following values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DeferBlockState.Placeholder&lt;/code&gt;: display the placeholder state of the block&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DeferBlockState.Loading&lt;/code&gt;: display the loading state of the block&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DeferBlockState.Error&lt;/code&gt;: display the error state of the block&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DeferBlockState.Complete&lt;/code&gt;: display the defer block as if the loading was complete&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This allows a fine-grained control of the state of the defer blocks.
If we want to test the same component as before, we can do:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; deferBlocks &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; fixture&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;getDeferBlocks&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// only one defer block should be found&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;expect&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(deferBlocks&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;length)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;toBe&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// Render the defer block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; deferBlocks[&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;render&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(DeferBlockState&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Complete)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// Check its content&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; loadedBlock &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; fixture&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;nativeElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;querySelector&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;expect&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(loadedBlock&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;textContent)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;toContain&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Some lazy-loaded content&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>Angular templates got better - the Control Flow syntax</title>
    <link href="https://blog.ninja-squad.com/2023/10/11/angular-control-flow-syntax"/>
    <updated>2023-10-11T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2023/10/11/angular-control-flow-syntax</id>
    <content type="html">
      &lt;p&gt;Angular v17 introduces a new &amp;quot;developer preview&amp;quot; feature called &amp;quot;control flow syntax&amp;quot;.
This feature allows you to use a new template syntax to write control flow statements, like if/else, for, and switch,
instead of using the built-in structural directives (&lt;code&gt;*ngIf&lt;/code&gt;, &lt;code&gt;*ngFor&lt;/code&gt;, and &lt;code&gt;*ngSwitch&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;To understand why this was introduced, let&amp;#39;s see how structural directives work in Angular.&lt;/p&gt;
&lt;h2&gt;Structural directives under the hood&lt;/h2&gt;
&lt;p&gt;Structural directives are directives that change the structure of the DOM by adding, removing, or manipulating elements.
They are easy to recognize in Angular because they begin with an asterisk &lt;code&gt;*&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But how do they &lt;em&gt;really&lt;/em&gt; work?&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s take a simple template with &lt;code&gt;ngIf&lt;/code&gt; and &lt;code&gt;ngFor&lt;/code&gt; directives as an example:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Ninja Squad&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; *ngIf&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;condition&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; *ngFor&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;let user of users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you read the chapter of our ebook about the Angular compiler,
you know that the framework generates JavaScript code from this template.
And maybe you imagine that &lt;code&gt;*ngIf&lt;/code&gt; gets converted to a JavaScript &lt;code&gt;if&lt;/code&gt;
and &lt;code&gt;*ngFor&lt;/code&gt; to a &lt;code&gt;for&lt;/code&gt; loop like:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;createElement&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (condition) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  createElement&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  for&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; of&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; users&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    createElement&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But Angular does not work exactly like that:
the framework decomposes the component&amp;#39;s template into &amp;quot;views&amp;quot;.
A view is a fragment of the template that has static HTML content.
It can have dynamic attributes and texts, but the HTML elements are stable.&lt;/p&gt;
&lt;p&gt;So our example generates in fact three views,
corresponding to three parts of the template:&lt;/p&gt;
&lt;p&gt;Main view:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Ninja Squad&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    &amp;#x3C;!-- special comment --&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;NgIf view:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  &amp;#x3C;!-- special comment --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;NgFor view:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is because the &lt;code&gt;*&lt;/code&gt; syntax is in fact syntactic sugar
to apply an attribute directive on an &lt;code&gt;ng-template&lt;/code&gt; element.
So our example is the same as:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Ninja Squad&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ng-template&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [ngIf]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;condition&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ng-template&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; ngFor&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [ngForOf]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; let-user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ng-template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ng-template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here &lt;code&gt;ngIf&lt;/code&gt; and &lt;code&gt;ngFor&lt;/code&gt; are plain directives.
Each &lt;code&gt;ng-template&lt;/code&gt; then generates a &amp;quot;view&amp;quot;.
Each view has a static structure that never changes.
But these views need to be dynamically inserted at some point.
And that&amp;#39;s where the &lt;code&gt;&amp;lt;!-- special comment --&amp;gt;&lt;/code&gt; comes into play.&lt;/p&gt;
&lt;p&gt;Angular has the concept of &lt;code&gt;ViewContainer&lt;/code&gt;.
A &lt;code&gt;ViewContainer&lt;/code&gt; is like a box where you can insert/remove child views.
To mark the location of these containers,
Angular uses a special HTML comment in the created DOM.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s what &lt;code&gt;ngIf&lt;/code&gt; actually does under the hood:
it creates a &lt;code&gt;ViewContainer&lt;/code&gt;, and then, when the condition given as input changes,
it inserts or removes the child view at the location of the special comment.&lt;/p&gt;
&lt;p&gt;This view concept is quite interesting as it will allow Angular
to only update views that consume a signal in the future,
and not the whole template of a component!
Check out out our &lt;a href=&quot;/2023/04/26/angular-signals/&quot;&gt;blog post about the Signal API&lt;/a&gt; for more details.&lt;/p&gt;
&lt;h2&gt;Custom structural directives&lt;/h2&gt;
&lt;p&gt;You can create your own structural directives if you want to.
Let&amp;#39;s say you want to write a &lt;code&gt;*customNgIf&lt;/code&gt; directive.
You can create a directive that takes a condition as an input and
injects a &lt;code&gt;ViewContainerRef&lt;/code&gt; (the service that allows to create the view)
and a &lt;code&gt;TemplateRef&lt;/code&gt; (the &lt;code&gt;ng-template&lt;/code&gt; on which the directive is applied).&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Directive&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; DoCheck&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; EmbeddedViewRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; TemplateRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; ViewContainerRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;@angular/core&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Directive&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  selector&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;[customNgIf]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  standalone&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; CustomNgIfDirective&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; DoCheck&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;   * The condition to check&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;   */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  @&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; alias&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;customNgIf&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;condition&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;!:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; boolean&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;   * The view created by the directive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;   */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  conditionalView&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; EmbeddedViewRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;any&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; null;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  constructor&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;     * The container where the view will be inserted&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; vcr&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ViewContainerRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;     * The template to render&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; tpl&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; TemplateRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;any&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  )&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;   * This method is called every time the change detection runs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;   */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  ngDoCheck&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // if the condition is true and the view is not created yet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;condition&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; !this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;conditionalView&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;      // create the view and insert it in the container&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;conditionalView&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;vcr&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;createEmbeddedView&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;tpl&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;!this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;condition&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;conditionalView&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;      // if the condition is false and the view is created&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;      // destroy the view&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;conditionalView&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;destroy&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;conditionalView&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; null;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works great!
And as you can see, it lets developers like us create powerful structural directives if we want to:
the built-in directives offered by Angular are not special in any way.&lt;/p&gt;
&lt;p&gt;But this approach has some drawbacks:
for example, it is a bit clunky to have an &lt;code&gt;else&lt;/code&gt; alternative with &lt;code&gt;*ngIf&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; *ngIf&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;condition; else elseBlock&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;If&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ng-template&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; #elseBlock&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Else&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ng-template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;elseBlock&lt;/code&gt; is another input of the &lt;code&gt;NgIf&lt;/code&gt; directive,
of type &lt;code&gt;TemplateRef&lt;/code&gt;, that the directive will display if the condition is falsy.
But this is not very intuitive to use, so we often see this instead:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; *ngIf&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;condition&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;If&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; *ngIf&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;!condition&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Else&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The structural directives are also not perfect type-checking-wise.
Even if Angular does some magic (with some special fields called &lt;code&gt;ngTemplateGuard&lt;/code&gt; in the directives to help the type-checker),
some cases are too tricky to handle.
For example, the &amp;quot;else&amp;quot; alternative of &lt;code&gt;*ngIf&lt;/code&gt; is not type-checked:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; *ngIf&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;!user; else userNotNullBlock&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;No user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ng-template&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; #userNotNullBlock&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    &amp;#x3C;!-- should compile as user is not null here --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    &amp;#x3C;!-- but it doesn&apos;t --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    {{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ng-template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;NgSwitch&lt;/code&gt; is even worse, as it consists of 3 separate directives
&lt;code&gt;NgSwitch&lt;/code&gt;, &lt;code&gt;NgSwitchCase&lt;/code&gt;, and &lt;code&gt;NgSwitchDefault&lt;/code&gt;.
The compiler has no idea if the &lt;code&gt;NgSwitchCase&lt;/code&gt; is used in the right context.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;&amp;#x3C;!-- user.type can be `&apos;user&apos; | &apos;anonymous&apos;` --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ng-container&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [ngSwitch]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;user.type&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; *ngSwitchCase&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;&apos;user&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  &amp;#x3C;!-- compiles even if user.type can&apos;t be &apos;admin&apos; --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; *ngSwitchCase&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;&apos;admin&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Admin&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; *ngSwitchDefault&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Unknown&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ng-container&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&amp;#39;s also worth noting that the &lt;code&gt;*&lt;/code&gt; syntax is not very intuitive for beginners.
And structural directives depend on the &lt;code&gt;ngDoCheck&lt;/code&gt; lifecycle hook,
which is tied to &lt;code&gt;zone.js&lt;/code&gt;.
In a future world where our components use the new Signal API
and don&amp;#39;t need &lt;code&gt;zone.js&lt;/code&gt; anymore,
structural directives would still force us to drag &lt;code&gt;zone.js&lt;/code&gt; in our bundle.&lt;/p&gt;
&lt;p&gt;So, to sum up, structural directives are powerful but have some drawbacks.
Fixing these drawbacks would require a lot of work in the compiler and the framework.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s why the Angular team decided to introduce a new syntax to write control flow statements in templates!&lt;/p&gt;
&lt;h2&gt;Control flow syntax&lt;/h2&gt;
&lt;p&gt;The control flow syntax is a new syntax introduced in Angular v17
to write control flow statements in templates.&lt;/p&gt;
&lt;p&gt;The syntax is very similar to some other templating syntaxes you may have met in the past,
and even to JavaScript itself.
There have been some debates and polling in the community about the various alternatives,
and the &lt;code&gt;@-syntax&lt;/code&gt; proposal won.&lt;/p&gt;
&lt;p&gt;With the control flow syntax, our previous template with &lt;code&gt;*ngIf&lt;/code&gt; and &lt;code&gt;*ngFor&lt;/code&gt; can be rewritten as:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Ninja Squad&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (condition) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;    @for&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (user &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; track&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;id) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This syntax is interpreted by the Angular compiler and creates the same views as the previous template,
but without the overhead of creating the structural directives,
so it is also a tiny bit more performant
(as it uses brand new compiled instructions under the hood in the generated code).
As this is not directives, the type-checking is also much better.&lt;/p&gt;
&lt;p&gt;And, cherry on the cake, the syntax is more powerful than the structural directives!&lt;/p&gt;
&lt;p&gt;The drawback is that this syntax uses &lt;code&gt;@&lt;/code&gt;, &lt;code&gt;{&lt;/code&gt; and &lt;code&gt;}&lt;/code&gt; characters with a special meaning,
so you can&amp;#39;t use these characters in your templates anymore,
and have to use equivalent HTML entities instead (&lt;code&gt;\&amp;amp;#64;&lt;/code&gt; for &lt;code&gt;@&lt;/code&gt;, &lt;code&gt;\&amp;amp;#123;&lt;/code&gt; for &lt;code&gt;{&lt;/code&gt;, and &lt;code&gt;\&amp;amp;#125;&lt;/code&gt; for &lt;code&gt;}&lt;/code&gt;).&lt;/p&gt;
&lt;h2&gt;If statement&lt;/h2&gt;
&lt;p&gt;As we saw above, a limitation of &lt;code&gt;NgIf&lt;/code&gt; is that it is a bit clunky to have an &lt;code&gt;else&lt;/code&gt; alternative.
And we can&amp;#39;t have an &lt;code&gt;else if&lt;/code&gt; alternative at all.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s no longer a problem with the control flow syntax:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (condition) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;condition is true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; @else if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (otherCondition) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;otherCondition is true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; @else&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;condition and otherCondition are false&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can still store the result of the condition in a variable if you want to,
which is really handy when used with an &lt;code&gt;async&lt;/code&gt; pipe for example:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (user$ &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;User is &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; @else if&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (isAdmin$ &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;User is admin&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; @else&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;No user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;For statement&lt;/h2&gt;
&lt;p&gt;With the control flow syntax, a for loop needs to specify a &lt;code&gt;track&lt;/code&gt; property,
which is the equivalent of the &lt;code&gt;trackBy&lt;/code&gt; function of &lt;code&gt;*ngFor&lt;/code&gt;.
Note that this is now mandatory, whereas it was optional with &lt;code&gt;*ngFor&lt;/code&gt;.
This is for performance reasons, as the Angular team found that very often,
developers were not using &lt;code&gt;trackBy&lt;/code&gt; when they should have.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  @for&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (user &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; track&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;id) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, this is a bit easier to use than the &lt;code&gt;trackBy&lt;/code&gt; function of &lt;code&gt;*ngFor&lt;/code&gt;
which requires to write a function.
Here we can directly specify the property of the item that is unique,
and the compiler will generate the function for us.
If you don&amp;#39;t have a unique property, you can still use a function or just use the loop variable itself
(which is equivalent to what &lt;code&gt;*ngFor&lt;/code&gt; currently does when no &lt;code&gt;trackBy&lt;/code&gt; is specified).&lt;/p&gt;
&lt;p&gt;One of the very useful additions to the control flow syntax is the handling of empty collections.
Previously you had to use an &lt;code&gt;*ngIf&lt;/code&gt; to display a message
if the collection was &lt;code&gt;null&lt;/code&gt; or empty and then use &lt;code&gt;*ngFor&lt;/code&gt; to iterate over the collection.&lt;/p&gt;
&lt;p&gt;With the control flow syntax, you can do it with an &lt;code&gt;@empty&lt;/code&gt; clause:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  @for&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (user &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; track&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;id) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; @empty&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;No users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can still access the variables we used to have with &lt;code&gt;*ngFor&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$index&lt;/code&gt; to get the index of the current item&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$first&lt;/code&gt; to know if the current item is the first one&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$last&lt;/code&gt; to know if the current item is the last one&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$even&lt;/code&gt; to know if the current item is at an even index&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$odd&lt;/code&gt; to know if the current item is at an odd index&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$count&lt;/code&gt; to get the length of the collection&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Unlike with &lt;code&gt;*ngFor&lt;/code&gt;, you don&amp;#39;t have to alias these variables to use them,
but you still can if you need to, for example when using nested loops.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  @for&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (user &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; users&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; track&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; isOdd &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; $odd) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [class.grey]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;isOdd&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; $index &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; - &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is also worth noting that the control flow &lt;code&gt;@for&lt;/code&gt; uses
a new algorithm under the hood to update the DOM when the collection changes.
It should be quite a bit faster than the algorithm used by &lt;code&gt;*ngFor&lt;/code&gt;,
as it does not allocate intermediate maps in most cases.
Combined with the required &lt;code&gt;track&lt;/code&gt; property,
&lt;code&gt;for&lt;/code&gt; loops should be way faster in Angular applications by default.&lt;/p&gt;
&lt;h2&gt;Switch statement&lt;/h2&gt;
&lt;p&gt;This is probably where the new type-checking shines the most,
as using an impossible value in a case will now throw a compilation error!&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;@switch&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;type) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  @case&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; @case&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;anonymous&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Anonymous&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; @default&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Other&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that the switch statement does not support fall-through,
so you can&amp;#39;t have several cases grouped together.
It also does not check if all cases are covered,
so you won&amp;#39;t get a compilation error if you forget a case.
(but I hope it will, add a 👍 on &lt;a href=&quot;https://github.com/angular/angular/issues/52107&quot;&gt;this issue&lt;/a&gt; if you want this as well!).&lt;/p&gt;
&lt;p&gt;It&amp;#39;s also noteworthy that the &lt;code&gt;@switch&lt;/code&gt; statement uses strict equality (&lt;code&gt;===&lt;/code&gt;) to compare values,
whereas &lt;code&gt;*ngSwitch&lt;/code&gt; used to use loose equality (&lt;code&gt;==&lt;/code&gt;).
Angular v17 introduced a breaking change, and &lt;code&gt;*ngSwitch&lt;/code&gt; now uses strict equality too,
with a warning in the console during development if you use loose equality:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;NG02001: As of Angular v17 the NgSwitch directive &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;uses strict equality comparison === instead of == to match different cases. &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Previously the case value &quot;1&quot; matched switch expression value &quot;&apos;1&apos;&quot;, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;but this is no longer the case with the stricter equality check.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Your comparison results return different results using === vs. ==&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;and you should adjust your ngSwitch expression and / or values&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;to conform with the strict equality requirements.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The future of templating 🚀&lt;/h2&gt;
&lt;p&gt;The control flow syntax is a new &amp;quot;developer preview&amp;quot; feature introduced in Angular v17,
and will probably be the recommended way to write templates in the future
(the plan is to make it stable in v18 once it has been battle-tested).&lt;/p&gt;
&lt;p&gt;It doesn&amp;#39;t mean that structural directives will be deprecated,
but the Angular team will likely focus on the control flow syntax in the future
and push them forward as the recommended solution.&lt;/p&gt;
&lt;p&gt;We will even have an automated migration to convert structural directives
to control flow statements in existing applications.
The migration is available in Angular v17 as a developer preview.
If you want to give it a try, run:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ng g @angular/core:control-flow&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This automatically migrates all your templates to the new syntax!
You can also run the migration against a single file with the &lt;code&gt;--path&lt;/code&gt; option:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ng g @angular/core:control-flow --path src/app/app.component.html&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Even though the new control flow is experimental,
v17 comes with a mandatory migration needed to support this new control flow syntax,
which consists in converting the &lt;code&gt;@&lt;/code&gt;, &lt;code&gt;{&lt;/code&gt; and &lt;code&gt;}&lt;/code&gt; characters used in your templates to their HTML entities.
This migration is run automatically when you update the app with &lt;code&gt;ng update&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The future of Angular is exciting!&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>What&apos;s new in Angular 16.2?</title>
    <link href="https://blog.ninja-squad.com/2023/08/09/what-is-new-angular-16.2"/>
    <updated>2023-08-09T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2023/08/09/what-is-new-angular-16.2</id>
    <content type="html">
      &lt;p&gt;Angular&amp;nbsp;16.2.0 is here!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;a href=&quot;https://github.com/angular/angular/releases/tag/16.2.0&quot;&gt;
    &lt;img class=&quot;img-fluid&quot; src=&quot;/assets/images/angular.png&quot; alt=&quot;Angular logo&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;This is a minor release with some nice features: let&amp;#39;s dive in!&lt;/p&gt;
&lt;h2&gt;Binding inputs of NgComponentOutlet&lt;/h2&gt;
&lt;p&gt;It used to be cumbersome to pass input data to a dynamic component
(you could do it, but you needed to use a provider and inject it).
It&amp;#39;s now way easier:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  selector&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;app-user&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  standalone&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{{&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; name &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}}&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; UserComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  @&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; required&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;!:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then to dynamically insert the component with inputs:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  selector&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;app-root&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  standalone&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  imports&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [NgComponentOutlet]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; *ngComponentOutlet&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;userComponent; inputs: userData&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; AppComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  userComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; UserComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  userData&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Cédric&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;afterRender and afterNextRender&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;afterRender&lt;/code&gt; and &lt;code&gt;afterNextRender&lt;/code&gt; lifecycle hooks have been added to the framework as developer preview APIs.
They are parts of the Signal API, see &lt;a href=&quot;https://github.com/angular/angular/discussions/49682&quot;&gt;the RFC discussion&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;They allow to run code after the component has been rendered the first time (&lt;code&gt;afterNextRender&lt;/code&gt;), or after every render (&lt;code&gt;afterRender&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The first one is useful to run code that needs to access the DOM, like calling a third-party library like we currently do in &lt;code&gt;ngAfterViewInit&lt;/code&gt;.
But, unlike &lt;code&gt;ngAfterViewInit&lt;/code&gt; and other lifecycle methods,
these hooks do not run during server-side rendering,
which makes them easier to use for SSR applications.&lt;/p&gt;
&lt;p&gt;You can now write:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; Component&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; ElementRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; ViewChild&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; afterNextRender&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;@angular/core&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  selector&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;app-chart&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  standalone&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;canvas&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; #canvas&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;canvas&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ChartComponent&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  @&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;ViewChild&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;canvas&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;canvas&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;!:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; ElementRef&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;HTMLCanvasElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  constructor&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    afterNextRender&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;      const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; ctx&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; this.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;canvas&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;nativeElement&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;      new&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; Chart&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;ctx&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;line&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; data&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;RouterTestingHarness&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;RouterTestingHarness&lt;/code&gt;, introduced in v15.2 (check out our &lt;a href=&quot;/2023/02/23/what-is-new-angular-15.2&quot;&gt;blog post&lt;/a&gt;),
now exposes the underlying fixture, allowing to use its methods and properties and making it compatible with testing libraries that expect a fixture (like &lt;a href=&quot;https://github.com/Ninja-Squad/ngx-speculoos&quot;&gt;ngx-speculoos&lt;/a&gt;).&lt;/p&gt;
&lt;h2&gt;Devtools&lt;/h2&gt;
&lt;p&gt;Some preliminary work has been done in the framework to trace what is injected in an application in dev mode.
This will be used in the future to improve the devtools experience, 
by providing a way to see what is injected in a component, and where it comes from.&lt;/p&gt;
&lt;h2&gt;Angular CLI&lt;/h2&gt;
&lt;p&gt;The CLI has been updated to v16.2.0 as well, with a few new features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the esbuild builder now adds preload hints based on its analysis of the application initial files&lt;/li&gt;
&lt;li&gt;the esbuild builder can now build the server bundle&lt;/li&gt;
&lt;li&gt;the esbuild builder now has experimental support for serving the application in SSR mode with the Vite-based dev-server&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;That&amp;#39;s all for this release, stay tuned!&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>What&apos;s new in Angular 16.1?</title>
    <link href="https://blog.ninja-squad.com/2023/06/14/what-is-new-angular-16.1"/>
    <updated>2023-06-14T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2023/06/14/what-is-new-angular-16.1</id>
    <content type="html">
      &lt;p&gt;Angular&amp;nbsp;16.1.0 is here!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;a href=&quot;https://github.com/angular/angular/releases/tag/16.1.0&quot;&gt;
    &lt;img class=&quot;img-fluid&quot; src=&quot;/assets/images/angular.png&quot; alt=&quot;Angular logo&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;This is a minor release with some nice features: let&amp;#39;s dive in!&lt;/p&gt;
&lt;h2&gt;TypeScript 5.1 support&lt;/h2&gt;
&lt;p&gt;Angular v16.1 now supports TypeScript 5.1. This means that you can use the latest version of TypeScript in your Angular applications. You can check out the &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-1/&quot;&gt;TypeScript 5.1 release notes&lt;/a&gt; to learn more about the new features.&lt;/p&gt;
&lt;h2&gt;Transform input values&lt;/h2&gt;
&lt;p&gt;Angular v16.1 introduces a new &lt;code&gt;transform&lt;/code&gt; option in the &lt;code&gt;@Input&lt;/code&gt; decorator.
It allows transforming the value passed to the input before it is assigned to the property.
The &lt;code&gt;transform&lt;/code&gt; option takes a function that takes the value as input and returns the transformed value.
As the most common use cases are to transform a string to a number or a boolean, Angular provides two built-in functions to do that: &lt;code&gt;numberAttribute&lt;/code&gt; and &lt;code&gt;booleanAttribute&lt;/code&gt; in &lt;code&gt;@angular/core&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here is an example of using &lt;code&gt;booleanAttribute&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; transform&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; booleanAttribute &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) disabled &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will transform the value passed to the input to a boolean so that the following code will work:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;my-component&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; disabled&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;my-component&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;my-component&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; disabled&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;my-component&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;&amp;#x3C;!-- Before, only the following was properly working --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;my-component&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [disabled]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;my-component&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;numberAttribute&lt;/code&gt; function works the same way but transforms the value to a number.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; transform&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; numberAttribute &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) value &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It also allows to define a fallback value, in case the input is not a proper number (default is NaN):&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; transform&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; unknown&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; numberAttribute&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 42&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;) value &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can then be used like this:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;my-component&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;42&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;my-component&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;my-component&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;not a number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;my-component&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;&amp;#x3C;!-- Before, only the following was properly working --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;my-component&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; [value]&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;42&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;my-component&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Fetch backend for the Angular HTTP client&lt;/h2&gt;
&lt;p&gt;The HTTP client has a new backend implementation based on the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API&quot;&gt;Fetch API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is an experimental and opt-in feature, that you can enable with:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;provideHttpClient&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;withFetch&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It does not support the progress reports on uploads,
and of course, requires a browser that supports the Fetch API.
The fetch API is also experimental on Node but available without flags from Node 18 onwards.&lt;/p&gt;
&lt;p&gt;This is mainly interesting for server-side rendering, as the XHR implementation is not supported natively in Node and requires a polyfill (which has some issues).&lt;/p&gt;
&lt;h2&gt;Angular CLI&lt;/h2&gt;
&lt;p&gt;The CLI now has a &lt;code&gt;--force-esbuild&lt;/code&gt; option that allows forcing the usage of esbuild for &lt;code&gt;ng serve&lt;/code&gt;.
It allows trying the esbuild implementation without switching the builder in &lt;code&gt;angular.json&lt;/code&gt; (and keeping the Webpack implementation for the &lt;code&gt;ng build&lt;/code&gt; command).&lt;/p&gt;
&lt;p&gt;The esbuild builder has been improved. It now pre-bundles the dependencies using the underlying &lt;a href=&quot;https://vitejs.dev/guide/dep-pre-bundling.html&quot;&gt;Vite mechanism&lt;/a&gt;, uses some persistent cache for the TypeScript compilation and Vite pre-bundling, and shows the estimated transfer sizes of the built assets as the Webpack builder does.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;That&amp;#39;s all for this release, stay tuned!&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>What&apos;s new in Vue 3.3?</title>
    <link href="https://blog.ninja-squad.com/2023/05/15/what-is-new-vue-3.3"/>
    <updated>2023-05-15T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2023/05/15/what-is-new-vue-3.3</id>
    <content type="html">
      &lt;p&gt;Vue&amp;nbsp;3.3.0 is here!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;a href=&quot;https://github.com/vuejs/core/blob/main/CHANGELOG.md#330-rurouni-kenshin-2023-05-11&quot;&gt;
    &lt;img class=&quot;img-fluid&quot; style=&quot;max-width: 60%&quot; src=&quot;/assets/images/vue.webp&quot; alt=&quot;Vue logo&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;The last minor release was v3.2.0 in August 2021!
Since then, we have seen a lot of patch releases,
some coming with new features.&lt;/p&gt;
&lt;p&gt;Originally, the v3.3 release was supposed to bring 
Suspense and the Reactivity Transform APIs out of
their experimental state.&lt;/p&gt;
&lt;p&gt;Is that the case? 
Let&amp;#39;s see what we have in this release (and some interesting bits from the 47 patches since v3.2.0)!&lt;/p&gt;
&lt;h2&gt;Hello Reactivity Transform, and goodbye!&lt;/h2&gt;
&lt;p&gt;During the last year and a half, the Vue team pursued its experiments with ref sugar
(see our &lt;a href=&quot;/2021/08/10/what-is-new-vue-3.2/&quot;&gt;previous blog post&lt;/a&gt; to catch up).&lt;/p&gt;
&lt;p&gt;Currently, without ref sugar, you write code like this:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; computed&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; watchEffect&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;vue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; quantity &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; total &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; computed&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; quantity&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;watchEffect&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;New total &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;total&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note the &lt;code&gt;.value&lt;/code&gt; that you need to access the value of the &lt;code&gt;quantity&lt;/code&gt; or &lt;code&gt;total&lt;/code&gt; ref.
If you use the Composition API, you&amp;#39;re used to it.&lt;/p&gt;
&lt;p&gt;The reactivity transform experiment introduced new compiler macros like &lt;code&gt;$ref()&lt;/code&gt; and &lt;code&gt;$computed()&lt;/code&gt;.
When using these, the variable becomes reactive:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; watchEffect&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;vue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; quantity &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; $ref&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; total &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; $computed&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; quantity &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;watchEffect&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;New total &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;total&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And &lt;code&gt;.value&lt;/code&gt; was no longer necessary with this syntax!&lt;/p&gt;
&lt;p&gt;But it turns out that this experiment is not quite as perfect as hoped initially.
It introduced another way to do the same thing, with quite a bit of &amp;quot;magic&amp;quot;,
additional pitfalls, and complexity.&lt;/p&gt;
&lt;p&gt;So in the end, this experiment is now officially... dropped!&lt;/p&gt;
&lt;p&gt;As some teams already started to use it, it will not be removed right away.
The plan is to phase these APIs out in a different package, add deprecation warnings in core,
and eventually remove them in v3.4.&lt;/p&gt;
&lt;p&gt;It doesn&amp;#39;t mean that the team is not thinking about Vue how can be improved.
Some new ideas will probably be shared publicly soon.&lt;/p&gt;
&lt;p&gt;And a part of the reactivity transform experiment is going to stay: the &lt;code&gt;defineProps&lt;/code&gt; destructuration.
It&amp;#39;s &lt;em&gt;the&lt;/em&gt; part I really liked, so I&amp;#39;m quite happy about it 🤓.&lt;/p&gt;
&lt;h2&gt;defineProps destructuration&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;defineProps&lt;/code&gt; is the way to declare your props in the script setup syntax
(see &lt;a href=&quot;/2021/09/30/script-setup-syntax-in-vue-3/&quot;&gt;our article about script setup&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The syntax plays well with TypeScript, but the declaration of default values was a bit painful:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; props &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; withDefaults&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;defineProps&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;?:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Hello&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(props&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;name)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You also can&amp;#39;t destructure the props directly, as it loses the reactivity.&lt;/p&gt;
&lt;p&gt;With this new release, you can now give default values while destructuring the props and keeping the reactivity!&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; name &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Hello&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; defineProps&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;?:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(name)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you try to use a destructured prop directly inside a watcher (or to &lt;code&gt;toRef&lt;/code&gt;),
Vue will issue a warning and indicate to use a getter function instead:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;watch&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// &quot;name&quot; is a destructured prop and should not be passed directly to watch().&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// Pass a getter () =&gt; name instead.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To help with this pattern, a new &lt;code&gt;toValue&lt;/code&gt; helper function has been added
to convert refs and getters to values:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; v1 &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; toValue&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;ref&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;hello&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // &apos;hello&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; v2 &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; toValue&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;hello&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // &apos;hello&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you want to give it a try, you&amp;#39;ll need to enable the &lt;code&gt;propsDestructure&lt;/code&gt; option
in your bundler config. For example, in Vite:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;plugins&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  vue&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    script&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      propsDestructure&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;TypeScript improvements&lt;/h2&gt;
&lt;p&gt;The TypeScript support of &lt;code&gt;defineProps&lt;/code&gt; and other macros has been massively improved,
as pretty much all built-in types are now supported (&lt;code&gt;Extract&lt;/code&gt;, &lt;code&gt;Exclude&lt;/code&gt;, &lt;code&gt;Uppercase&lt;/code&gt;, &lt;code&gt;Parameters&lt;/code&gt;, etc.).
It also can now refer to types and interfaces imported from other files
(whereas it was only resolving local types previously).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;defineEmits&lt;/code&gt; has also been improved,
as it now supports a shorter TS declaration.
In Vue v3.2, we used to write the type like this:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; emit &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; defineEmits&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;selected&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; number&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;):&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;// emit(&apos;selected&apos;, 14)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is now a simplified syntax in Vue v3.3.
You can use an interface with the events as keys,
and the arguments as tuples:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; emit &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; defineEmits&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  selected&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; number&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Vue&amp;nbsp;3.3 also allows writing TypeScript directly in templates.
It can be handy to hint to &lt;a href=&quot;https://github.com/johnsoncodehk/volar&quot;&gt;Volar&lt;/a&gt; that a
variable is not null, or of a particular type:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Welcome {{ (user!.name as string).toLowerCase() }}&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Generic components&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;script setup&lt;/code&gt; components can now have a generic parameter,
which works like a generic &lt;code&gt;&amp;lt;T&amp;gt;&lt;/code&gt; in TypeScript:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; setup&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; lang&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ts&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; generic&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;defineProps&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; T&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; items&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; Array&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Volar is then capable to throw an error if
&lt;code&gt;value&lt;/code&gt; is a &lt;code&gt;string&lt;/code&gt; and &lt;code&gt;items&lt;/code&gt; an array of numbers for example.&lt;/p&gt;
&lt;h2&gt;Component name inference&lt;/h2&gt;
&lt;p&gt;When using the script setup syntax, the SFC compiler now infers the component name
based on the file name.&lt;/p&gt;
&lt;p&gt;So a component declared in a file named &lt;code&gt;Home.vue&lt;/code&gt; will automatically have the name &lt;code&gt;Home&lt;/code&gt; since v3.2.34.&lt;/p&gt;
&lt;h2&gt;defineOptions macro&lt;/h2&gt;
&lt;p&gt;A new macro (a compile-time helper like &lt;code&gt;defineProps&lt;/code&gt; and &lt;code&gt;defineEmits&lt;/code&gt;) has been introduced
to help declare the options of a component.
This is available only in &lt;code&gt;script setup&lt;/code&gt; component,
and can be handy to declare a few things like the name of a component,
if the inferred name is not good enough
or to set the &lt;code&gt;inheritAttrs&lt;/code&gt; option:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;defineOptions&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;Home&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; inheritAttrs&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;defineSlots macro&lt;/h2&gt;
&lt;p&gt;Another macro called &lt;code&gt;defineSlots&lt;/code&gt; (and a &lt;code&gt;slots&lt;/code&gt; option if you&amp;#39;re using &lt;code&gt;defineComponent&lt;/code&gt;)
has been added to the framework to help declare typed slots.
When doing so, Volar will be able to check the slot props of a component.
Let&amp;#39;s say an &lt;code&gt;Alert&lt;/code&gt; component has a default slot that exposes a &lt;code&gt;close&lt;/code&gt; function:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;defineSlots&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;  default&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;props&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; close&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; })&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the &lt;code&gt;Alert&lt;/code&gt; component is not used properly, then Volar throws an error:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;Alert&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; #default&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;{ closeAlert }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;Alert&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;// error TS2339: Property &apos;closeAlert&apos; does not exist on type &apos;{ close: () =&gt; void; }&apos;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The returning value of &lt;code&gt;defineProps&lt;/code&gt; can be used
and is the same object as returned by &lt;code&gt;useSlots&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;experimental defineModel macro&lt;/h2&gt;
&lt;p&gt;When you have a custom form component that just wants to bind the &lt;code&gt;v-model&lt;/code&gt; value to a classic input, the prop/event mechanic we saw can be a bit cumbersome:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; :value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;modelValue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; @input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;setValue($event.target.value)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; setup&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; lang&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ts&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;defineProps&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;{&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; modelValue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; emit &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; defineEmits&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;{&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;update:modelValue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; setValue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;pickedValue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  emit&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;update:modelValue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; pickedValue&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is now possible to simplify this component,
by using the &lt;code&gt;defineModel&lt;/code&gt; (experimental) macro:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; v-model&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;modelValue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; setup&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; lang&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ts&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; modelValue &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; defineModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;defineModel&lt;/code&gt; also accepts a few options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;required: true&lt;/code&gt; indicates that the prop is required&lt;/li&gt;
&lt;li&gt;&lt;code&gt;default: value&lt;/code&gt; lets specify a default value&lt;/li&gt;
&lt;li&gt;&lt;code&gt;local: true&lt;/code&gt; indicates that the prop is available and mutable even if the parent component did not pass the matching v-model&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A &lt;code&gt;useModel&lt;/code&gt; helper is also available if you don&amp;#39;t use &lt;code&gt;script setup&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Note that this feature is experimental and opt-in.
For example, in Vite:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFCB6B&quot;&gt;plugins&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  vue&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;    script&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F07178&quot;&gt;      defineModel&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;default value for toRef&lt;/h2&gt;
&lt;p&gt;It is now possible to define a default value when using &lt;code&gt;toRef()&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; order &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; quantity&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; undefined&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; quantity &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; toRef&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(order&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;quantity&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt; // quantity is 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that this works only if the value is &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;isShallow&lt;/h2&gt;
&lt;p&gt;A new utility function called &lt;code&gt;isShallow&lt;/code&gt; is now available.
It allows checking if a variable is deeply reactive (created with &lt;code&gt;ref&lt;/code&gt; or &lt;code&gt;reactive&lt;/code&gt;)
or &amp;quot;shallow&amp;quot; (created with &lt;code&gt;shallowRef&lt;/code&gt; or &lt;code&gt;shallowReactive&lt;/code&gt;).&lt;/p&gt;
&lt;h2&gt;v-for and ref&lt;/h2&gt;
&lt;p&gt;Vue 3 now behaves like Vue 2 used to behave when using &lt;code&gt;ref&lt;/code&gt; inside &lt;code&gt;v-for&lt;/code&gt;:
it populates an array of refs.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; setup&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;vue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; divs &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;([])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; v-for&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;i of 3&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;divs&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;{{ i }}&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  &amp;#x3C;!-- divs is populated with an array of 3 refs --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  &amp;#x3C;!-- one for each HTMLDivElement created --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;{{ divs }}&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;aliases for vnode hook events&lt;/h2&gt;
&lt;p&gt;Vue allows you to listen for lifecycle events in templates, both for elements and components.
The syntax in Vue 3 is &lt;code&gt;@vnodeMounted&lt;/code&gt; for example.
In Vue v3.3, it is now possible to use &lt;code&gt;@vue:mounted&lt;/code&gt; instead,
which is a bit more understandable.
&lt;code&gt;@vnode&lt;/code&gt; hooks are now deprecated.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; setup&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;vue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; isMounted &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; onDivMounted &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; isMounted&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; condition &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;setTimeout&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; condition&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#FF9CAC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 3000&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;isMounted: {{ isMounted }}&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; @vue:mounted&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;onDivMounted()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; v-if&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;condition&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;Hello&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can try this example in this &lt;a href=&quot;https://play.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cD5cbmltcG9ydCB7IHJlZiB9IGZyb20gJ3Z1ZSdcblxuY29uc3QgaXNNb3VudGVkID0gcmVmKGZhbHNlKVxuY29uc3Qgb25EaXZNb3VudGVkID0gKCkgPT4gaXNNb3VudGVkLnZhbHVlID0gdHJ1ZSBcblxuY29uc3QgY29uZGl0aW9uID0gcmVmKGZhbHNlKVxuc2V0VGltZW91dCgoKSA9PiBjb25kaXRpb24udmFsdWUgPSB0cnVlLCAzMDAwKVxuPC9zY3JpcHQ+XG5cbjx0ZW1wbGF0ZT5cbiAgPGRpdj5pc01vdW50ZWQ6IHt7IGlzTW91bnRlZCB9fTwvZGl2PlxuICA8ZGl2IEB2dWU6bW91bnRlZD1cIm9uRGl2TW91bnRlZCgpXCIgdi1pZj1cImNvbmRpdGlvblwiPkhlbGxvPC9kaXY+XG48L3RlbXBsYXRlPiIsImltcG9ydC1tYXAuanNvbiI6IntcbiAgXCJpbXBvcnRzXCI6IHtcbiAgICBcInZ1ZVwiOiBcImh0dHBzOi8vdW5wa2cuY29tL0B2dWUvcnVudGltZS1kb21AMy4yLjI2L2Rpc3QvcnVudGltZS1kb20uZXNtLWJyb3dzZXIuanNcIlxuICB9XG59In0=&quot;&gt;online demo&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;suspensible Suspense&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Suspense&lt;/code&gt; is still experimental but gained a new prop called &lt;code&gt;suspensible&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The prop allows the suspense to be captured by the parent suspense.
That can be useful if you have nested &lt;code&gt;Suspense&lt;/code&gt; components,
as you can see in the &lt;a href=&quot;https://github.com/vuejs/core/pull/6736&quot;&gt;PR explanation&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;console available in templates&lt;/h2&gt;
&lt;p&gt;A small (but useful when debugging) improvement in templates is the possibility
to directly use &lt;code&gt;console&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; @input&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;console.log($event.target.value)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To conclude, let&amp;#39;s see what happened in the ecosystem recently.&lt;/p&gt;
&lt;h2&gt;create-vue&lt;/h2&gt;
&lt;p&gt;Since Vue v3.2, the Vue team started a new project called &lt;a href=&quot;https://github.com/vuejs/create-vue&quot;&gt;create-vue&lt;/a&gt;,
which is now the recommended way to start a Vue project.
You can use it with&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm init vue@next&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;create-vue&lt;/code&gt; is based on Vite v4,
and officially replaces Vue CLI.&lt;/p&gt;
&lt;p&gt;If you missed it, &lt;code&gt;create-vue&lt;/code&gt; recently added the support of Playwright in addition to Cypress for e2e tests!
It now also supports TypeScript v5 out of the box.&lt;/p&gt;
&lt;h2&gt;Router&lt;/h2&gt;
&lt;p&gt;Vue v3.3 introduced a new function on the object returned by &lt;code&gt;createApp&lt;/code&gt;:
&lt;code&gt;runWithContext&lt;/code&gt;.
The function allows using &lt;code&gt;inject&lt;/code&gt; with the app as the active instance,
and get the value provided by the app providers.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; app &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; createApp&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;/* ... */&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;provide&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;token&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;runWithContext&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; inject&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;token&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If I mention this in the router section,
it&amp;#39;s because it unlocks the possibility to use &lt;code&gt;inject&lt;/code&gt; in global navigation guards
if you use Vue v3.3 and the router v4.2!&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;router&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;beforeEach&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt;to&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8;font-style:italic&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;  console&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;inject&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;token&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Pinia&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://pinia.vuejs.org/&quot;&gt;Pinia&lt;/a&gt; is a state-management library
from the author of vue-router &lt;a href=&quot;https://twitter.com/posva&quot;&gt;Eduardo &amp;quot;@posva&amp;quot;&lt;/a&gt;.
It was meant as an experiment for Vuex v5,
but it turns out to be very good,
and it&amp;#39;s now the official recommendation for state-management library in Vue 3 projects.&lt;/p&gt;
&lt;p&gt;The project moved into the vuejs organization, and there will be no Vuex version 5.
Pinia is a really cool project, with a great composition API and TS support,
and one of the cutest logos you&amp;#39;ve ever seen.&lt;/p&gt;
&lt;p&gt;We added a complete chapter in &lt;a href=&quot;https://books.ninja-squad.com/vue&quot;&gt;our ebook&lt;/a&gt;
to explain how Pinia works if you&amp;#39;re interested 🤓.&lt;/p&gt;
&lt;p&gt;Eduardo also released &lt;a href=&quot;https://vuefire.vuejs.org/&quot;&gt;VueFire&lt;/a&gt;,
the official Firebase bindings for Vue 3.
With this library, you can add Firebase to your Vue or Nuxt projects in a few minutes.&lt;/p&gt;
&lt;h2&gt;Nuxt&lt;/h2&gt;
&lt;p&gt;After a long development, &lt;a href=&quot;https://nuxt.com/&quot;&gt;Nuxt&lt;/a&gt; v3 is now stable!
It is a really amazing solution and the Nuxt team has been hard at work
to provide a great development experience (with some dark magic under the hood).
Give it a try if you&amp;#39;re looking for a meta-framework on top of Vue
(for example if you need SSR or SSG for your project).&lt;/p&gt;
&lt;h2&gt;Volar&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/johnsoncodehk/volar&quot;&gt;Volar&lt;/a&gt; reached v1.0 recently
after a very intense period of development these past months.
The TypeScript support is now better than ever,
making it a no-brainer to use in your projects.&lt;/p&gt;
&lt;h2&gt;Vue Test utils&lt;/h2&gt;
&lt;p&gt;The testing library has a few typings improvements coming in the v2.4 release,
and now supports SSR testing via &lt;code&gt;renderToString&lt;/code&gt; since v2.3.&lt;/p&gt;
&lt;h2&gt;Vue 3 in 2023&lt;/h2&gt;
&lt;p&gt;The Vue team plans to release more frequent minor releases than in the past, so we can expect Vue v3.4 soon.
The next releases will be focused on bug fixes and small improvements in the first quarter of the year.
Then there should be some improvements for the SSR support in Q2.
Finally, the second half of the year should see the first alpha of Vapor.
We should hopefully also see Suspense finally getting out of its experimental state.&lt;/p&gt;
&lt;p&gt;Vue Vapor is an alternative compilation mode to get better performances.
It&amp;#39;s not public yet, but we already know that it is inspired by what &lt;a href=&quot;https://www.solidjs.com/&quot;&gt;Solidjs&lt;/a&gt; does,
as the reactivity system of Vue and Solid are fairly similar.
The idea is to compile a &lt;code&gt;script setup&lt;/code&gt; component differently when the &amp;quot;Vapor&amp;quot; mode is enabled,
resulting in a lighter rendering code (not using VDOM).&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s say we have a classic Counter component:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; setup&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; lang&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ts&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  let&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; count &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; @click&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;count++&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;{{ count }}&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the current Vue 3 compilation mode,
the template is compiled into a function that produces VDOM
which is then diffed and rendered
(check out the &amp;quot;Under the hood&amp;quot; chapter of our ebook if you want to learn more).
In Vapor mode, the template is compiled into a function that only updates what&amp;#39;s necessary in the DOM.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; effect&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;vue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; setText&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; on&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;vue/vapor&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; t0 &lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; template&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;&amp;#x3C;div&gt;&amp;#x3C;button&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  let&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt; t0&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  let&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;firstChild&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C792EA&quot;&gt;  let&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; button_text&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  effect&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;    // This is the only part that is executed at runtime when the counter value changes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;    setText&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; button_text&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;  on&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;click&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; div&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This &amp;quot;Vapor&amp;quot; mode will be opt-in at the component level, probably for &amp;quot;leaf&amp;quot; components first.
To switch a component to Vapor, the current idea is to import it with a &lt;code&gt;.vapor.vue&lt;/code&gt; extension:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; setup&lt;/span&gt;&lt;span style=&quot;color:#C792EA&quot;&gt; lang&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;ts&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // 👇 compiles the User component in Vapor mode&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#676E95;font-style:italic&quot;&gt;  // you get an error if the component is not &quot;Vapor&quot; compatible&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;  import&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; User &lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;./User.vapor.vue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#F07178&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#39;ll be able to enable it for a whole application in the future.
The current idea is to call a different &lt;code&gt;createApp&lt;/code&gt; function from &lt;code&gt;vue/vapor&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; createApp&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;vue/vapor&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt; App &lt;/span&gt;&lt;span style=&quot;color:#89DDFF;font-style:italic&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;./App.vapor.vue&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;createApp&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(App)&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#82AAFF&quot;&gt;mount&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#C3E88D&quot;&gt;#app&lt;/span&gt;&lt;span style=&quot;color:#89DDFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#BABED8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When enabled for a full application, the VDOM implementation could be completely dropped from the resulting bundle!
We can&amp;#39;t wait to try this!&lt;/p&gt;
&lt;p&gt;That&amp;#39;s all for this release. Stay tuned for the next one!&lt;/p&gt;
&lt;p&gt;Our &lt;a href=&quot;https://books.ninja-squad.com/vue&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://vue-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/vue&quot;&gt;training&lt;/a&gt; are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>What&apos;s new in Angular 16?</title>
    <link href="https://blog.ninja-squad.com/2023/05/03/what-is-new-angular-16.0"/>
    <updated>2023-05-03T00:00:00Z</updated>
    <id>https://blog.ninja-squad.com/2023/05/03/what-is-new-angular-16.0</id>
    <content type="html">
      &lt;p&gt;Angular&amp;nbsp;16.0.0 is here!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
  &lt;a href=&quot;https://github.com/angular/angular/releases/tag/16.0.0&quot;&gt;
    &lt;img class=&quot;img-fluid&quot; src=&quot;/assets/images/angular.png&quot; alt=&quot;Angular logo&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;This is a major release packed with features: let&amp;#39;s dive in!&lt;/p&gt;
&lt;h2&gt;Angular Signals&lt;/h2&gt;
&lt;p&gt;As you may have heard, all the hype around Angular is about the addition of Signals to the framework. As this is a big change that will shape how we build Angular applications in the future, we wrote an introduction to Signals, to cover what you can do with them in v16 and what to expect in the future:&lt;/p&gt;
&lt;p&gt;👉 &lt;a href=&quot;/2023/04/26/angular-signals/&quot;&gt;Angular Signals&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Note that Signals are released as a developer preview in v16 and the API may change in the future.&lt;/p&gt;
&lt;p&gt;As Signals are progressing, Angular now allows configuring ZoneJS explicitly with &lt;code&gt;provideZoneChangeDetection&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;bootstrapApplication(AppComponent, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  providers: [provideZoneChangeDetection({eventCoalescing: true})],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This opens the door to zoneless applications in the near future,
where developers could choose to not include ZoneJS in their application.&lt;/p&gt;
&lt;h2&gt;Required inputs&lt;/h2&gt;
&lt;p&gt;Angular v16 added the possibility to mark an input as required,
with &lt;code&gt;@Input({ required: true})&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;@Input({ required: true }) user!: UserModel;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In that case, if the parent component does not pass the input, 
then the compiler will throw an error.&lt;/p&gt;
&lt;p&gt;This has been a long-awaited feature, we&amp;#39;re happy to see this land in Angular!&lt;/p&gt;
&lt;h2&gt;Server-Side Rendering and progressive hydration&lt;/h2&gt;
&lt;p&gt;Angular has been supporting Server-Side Rendering (SSR) for a while now,
but it was a bit limited as it was only possible to render the whole application on the server, and then re-render it on the client when the JavaScript bundle was loaded.
This was resulting in a flickering when the application loaded,
as the DOM was completely wiped out before being re-rendered.&lt;/p&gt;
&lt;p&gt;Angular v16 introduces &amp;quot;progressive hydration&amp;quot;,
which allows rendering the application on the server,
and then progressively hydrate it on the client.&lt;/p&gt;
&lt;p&gt;This means that the server-rendered DOM is not wiped out anymore,
and the client-side rendering is done progressively,
which results in a much smoother experience for the user.&lt;/p&gt;
&lt;p&gt;To enable these new behaviors, you simply add &lt;code&gt;provideClientHydration()&lt;/code&gt; to your providers:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;bootstrapApplication(AppComponent, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  providers: [provideClientHydration()]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The HttpClient has also been updated to be able
to store the result of a request done on the server,
and then reuse it on the client during the hydration process!
The behavior is enabled by default if you use &lt;code&gt;provideClientHydration()&lt;/code&gt;,
but can be disabled with &lt;code&gt;provideClientHydration(withNoHttpTransferCache())&lt;/code&gt;.
You can also disable the DOM reuse with &lt;code&gt;withNoDomReuse()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Note that this is a developer preview, and the API may change in the future.
There are also a few pitfalls to be aware of.
For example, the HTML must be valid when generated on the server (whereas the browser is more forgiving).
The DOM must also be the same on the server and the client,
so you can&amp;#39;t manipulate the server-rendered DOM before sending it to the client.
If some parts of your templates don&amp;#39;t produce the same result on the server and the client, you can skip them by adding &lt;code&gt;ngSkipHydration&lt;/code&gt; to the element or component.
i18n is also not supported yet, but that should come soon.&lt;/p&gt;
&lt;p&gt;When running in development mode, the application will output some stats to the console to help you debug the hydration process:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Angular hydrated 19 component(s) and 68 node(s), 1 component(s) were skipped&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can easily give this a try by using Angular Universal.
In the long term, this will probably be part of the CLI directly.&lt;/p&gt;
&lt;h2&gt;DestroyRef&lt;/h2&gt;
&lt;p&gt;Angular v16 introduces a new &lt;code&gt;DestroyRef&lt;/code&gt; class,
which has only one method called &lt;code&gt;onDestroy&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;DestroyRef&lt;/code&gt; can be injected,
and then used to register code that should run
on the destruction of the surrounding context.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const destroyRef = inject(DestroyRef);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// register a destroy callback&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;destroyRef.onDestroy(() =&gt; doSomethingOnDestroy());&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For example, it can be used to execute code on the destruction
of a component or directive (as we do now with &lt;code&gt;ngOnDestroy&lt;/code&gt;).
But this is more useful for cases where you want to execute code
when a component is destroyed, but you don&amp;#39;t have access to the component itself,
for example when defining a utility function.&lt;/p&gt;
&lt;p&gt;This is exactly what Angular uses internally to implement &lt;code&gt;takeUntilDestroyed&lt;/code&gt;,
the new RXJS operator introduced in our &lt;a href=&quot;/2023/04/26/angular-signals/&quot;&gt;Signals blog post&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;provideServiceWorker&lt;/h2&gt;
&lt;p&gt;One of the last modules that needed to be transitioned to a standalone provider function was &lt;code&gt;ServiceWorkerModule&lt;/code&gt;. It is now done with &lt;code&gt;provideServiceWorker&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;bootstrapApplication(AppComponent, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  providers: [provideServiceWorker(&apos;ngsw-worker.js&apos;, { enabled: !isDevMode() })]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It, of course, accepts the same options as the &lt;code&gt;ServiceWorkerModule&lt;/code&gt;.
Running &lt;code&gt;ng add @angular/pwa&lt;/code&gt; will now add &lt;code&gt;provideServiceWorker&lt;/code&gt; to your providers
if your application is a standalone one.&lt;/p&gt;
&lt;h2&gt;TypeScript 5.0 support&lt;/h2&gt;
&lt;p&gt;Angular v16 now supports TypeScript 5.0. This means that you can use the latest version of TypeScript in your Angular applications. You can check out the &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/&quot;&gt;TypeScript 5.0 release notes&lt;/a&gt; to learn more about the new features.&lt;/p&gt;
&lt;p&gt;One important point is that TypeScript now supports the &amp;quot;official&amp;quot; decorator specification.
Their &amp;quot;experimental decorators&amp;quot; (based on a much older specification) are still supported but are now considered legacy. One of the differences between these two specifications is that the legacy one supports decorators on parameters, which is used by Angular for dependency injection (with &lt;code&gt;@Optional&lt;/code&gt;, &lt;code&gt;@Inject&lt;/code&gt;, etc.), and the new one doesn&amp;#39;t.&lt;/p&gt;
&lt;p&gt;It is now possible to use the new decorator specification in Angular, but it requires a few changes in your code, as you can&amp;#39;t use decorators on parameters anymore.
This can usually be worked around by using the &lt;code&gt;inject()&lt;/code&gt; function from &lt;code&gt;@angular/core&lt;/code&gt;.
There is no rush to use the new decorators instead of the &amp;quot;legacy&amp;quot; ones, but it&amp;#39;s something to keep in mind as I wouldn&amp;#39;t be surprised if we have to migrate away from &lt;code&gt;experimentalDecorators&lt;/code&gt; in the future&lt;/p&gt;
&lt;h2&gt;Styles removal opt-in&lt;/h2&gt;
&lt;p&gt;Angular v16 introduces a new opt-in feature to remove the styles of a component
when its last instance is destroyed.&lt;/p&gt;
&lt;p&gt;This will be the default behavior in the future, but you can already opt in with:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{ provide: REMOVE_STYLES_ON_COMPONENT_DESTROY, useValue: true }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Router&lt;/h2&gt;
&lt;p&gt;Angular v15.2 deprecated the usage of class-based guards and resolvers
(check out our &lt;a href=&quot;/2023/02/23/what-is-new-angular-15.2/&quot;&gt;blog post for more details&lt;/a&gt;).
In Angular v16, a migration will run to remove the guard and resolver interfaces from your code (&lt;code&gt;CanActivate&lt;/code&gt;, &lt;code&gt;Resolve&lt;/code&gt;, etc.).&lt;/p&gt;
&lt;p&gt;To help with the conversion, the router now offers helper functions to convert class-based entities to their function-based equivalent:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mapToCanActivate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mapToCanActivateChild&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mapToCanDeactivate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mapToCanMatch&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mapToResolve&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example, you can now write:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{ path: &apos;admin&apos;, canActivate: mapToCanActivate([AdminGuard]) };&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;RouterTestingModule&lt;/code&gt; is also getting phased out, and will probably be deprecated and removed in the future. It is not needed anymore, because Angular v16 now provides &lt;code&gt;MockPlatformLocation&lt;/code&gt; in &lt;code&gt;BrowserTestingModule&lt;/code&gt; by default, which was the main reason to use &lt;code&gt;RouterTestingModule&lt;/code&gt; in the first place.&lt;/p&gt;
&lt;p&gt;You can now directly use &lt;code&gt;RouterModule.forRoot([])&lt;/code&gt; or &lt;code&gt;providerRouter([])&lt;/code&gt; in your tests.&lt;/p&gt;
&lt;p&gt;Last but not least, the router now offers the possibility to bind parameters as inputs.&lt;/p&gt;
&lt;p&gt;To do so, you need to configure the router with &lt;code&gt;withComponentInputBinding&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;provideRouter(routes, withComponentInputBinding())&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this option, a component can declare an input with the same name as a route parameter,
query parameter or data, and Angular will automatically bind the value of the parameter or data to this input.&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export class RaceComponent implements OnChanges {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  @Input({ required: true }) raceId!: string;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can then use this input as a regular input, and react to its change with ngOnChanges or by using a setter for this input:&lt;/p&gt;
&lt;pre class=&quot;shiki material-theme-palenight&quot; style=&quot;background-color:#292D3E;color:#babed8&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;constructor(private raceService: RaceService) {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ngOnChanges() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  this.raceModel$ = this.raceService.get(this.raceId);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Angular CLI&lt;/h2&gt;
&lt;p&gt;Check out our &lt;a href=&quot;/2023/05/03/angular-cli-16.0/&quot;&gt;dedicated blog post about the CLI&lt;/a&gt; for more details.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;That&amp;#39;s all for this release, stay tuned!&lt;/p&gt;
&lt;p&gt;All our materials (&lt;a href=&quot;https://books.ninja-squad.com/angular&quot;&gt;ebook&lt;/a&gt;, &lt;a href=&quot;https://angular-exercises.ninja-squad.com/&quot;&gt;online training&lt;/a&gt; and &lt;a href=&quot;https://ninja-squad.com/training/angular&quot;&gt;training&lt;/a&gt;) are up-to-date with these changes if you want to learn more!&lt;/p&gt;

    </content>
  </entry>
</feed>