<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gianpiero Errigo</title>
    <description>The latest articles on DEV Community by Gianpiero Errigo (@gianpiero_errigo).</description>
    <link>https://dev.to/gianpiero_errigo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F914122%2F68493a37-b03c-42f0-9aa6-ccafb1de1fc0.png</url>
      <title>DEV Community: Gianpiero Errigo</title>
      <link>https://dev.to/gianpiero_errigo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gianpiero_errigo"/>
    <language>en</language>
    <item>
      <title>Angular 15: what happened to environment.ts</title>
      <dc:creator>Gianpiero Errigo</dc:creator>
      <pubDate>Fri, 27 Jan 2023 19:21:20 +0000</pubDate>
      <link>https://dev.to/playfulprogramming-angular/angular-15-what-happened-to-environmentts-koh</link>
      <guid>https://dev.to/playfulprogramming-angular/angular-15-what-happened-to-environmentts-koh</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR: Nothing!
&lt;/h2&gt;

&lt;p&gt;Angular 15 simply doesn't ship anymore environment files by default.&lt;br&gt;
You can still create them and configure their replacement based on build target as it was done automatically at project creation in previous versions.&lt;/p&gt;


&lt;h2&gt;
  
  
  A misunderstood purpose
&lt;/h2&gt;

&lt;p&gt;The origin of the confusion, arising lately about the missing of these files in new project created with &lt;code&gt;ng-cli&lt;/code&gt; at version 15, has its roots in the misconception that &lt;code&gt;src/environments/environment.ts&lt;/code&gt; and &lt;code&gt;src/environments/environment.prod.ts&lt;/code&gt; were some kind of sacred paths hardcoded in the deepest guts of Angular framework.&lt;br&gt;
Reality is that they were just a convenience default choice, with no reference in codebase, and that could have been substituted by different paths and names with no harm to the application.&lt;/p&gt;
&lt;h2&gt;
  
  
  Original role
&lt;/h2&gt;

&lt;p&gt;The only place in code where you could find them referenced at project creation was &lt;code&gt;main.ts&lt;/code&gt;, generated with something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./environments/environment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;production&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;enableProdMode&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Their &lt;code&gt;environment.production&lt;/code&gt; property was used to check if the build just booted had to enable &lt;code&gt;ProdMode&lt;/code&gt; or not.&lt;br&gt;
This function was turning off a flag (yes, the flag is indeed &lt;code&gt;isDevMode&lt;/code&gt;, and not &lt;code&gt;isProdMode&lt;/code&gt; like one could expect) actually checked in Angular codebase to toggle some "debugging" features, most evident of which is the familiar message logged in console &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Angular is running in development mode.&lt;br&gt;
Call enableProdMode() to enable production mode.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When the flag is &lt;code&gt;true&lt;/code&gt;, it means we are running a development stage of our app, so we want the framework to be more verbose in warnings and errors, and even to be a bit more "pedantic" checking situations that are not an error per-se, but that could lead to undesired and often erroneous behaviour in production.&lt;br&gt;
Famous one is surely &lt;a href="https://angular.io/errors/NG0100" rel="noopener noreferrer"&gt;NG0100: Expression has changed after it was checked&lt;/a&gt;, responsible of verifying our data-binding follows a unidirectional flow, something that &lt;strong&gt;could&lt;/strong&gt; bring problems during execution, but that will not throw errors on its own at runtime.&lt;/p&gt;

&lt;p&gt;Originally Angular had no way to switch this flag other than putting the function in a file parsed at bootstrap.&lt;/p&gt;
&lt;h2&gt;
  
  
  Black magic of file replacement
&lt;/h2&gt;

&lt;p&gt;People tended to accept the interpretation of the &lt;br&gt;
correct file to load as faith, without questioning &lt;strong&gt;how&lt;/strong&gt; the framework was capable of reading &lt;code&gt;environment.ts&lt;/code&gt; or &lt;code&gt;environment.prod.ts&lt;/code&gt; accordingly to the build target of choice.&lt;br&gt;
The answer was nothing involving deep understanding of Angular inner mechanisms, but just the use of a nice feature offered by its builder, that while parsing configuration for chosen target, was instructed to take in account &lt;code&gt;fileReplacements&lt;/code&gt; array, issuing the substitution defined in its objects.&lt;br&gt;
This was default config for &lt;strong&gt;production&lt;/strong&gt; build some versions ago:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"configurations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"production"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fileReplacements"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"replace"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/environments/environment.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"with"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/environments/environment.prod.ts"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing was preventing us to add new replacements or change default one but, if the latter, we should have considered to modify our &lt;code&gt;main.ts&lt;/code&gt; to check in the right file for the &lt;code&gt;environment.production&lt;/code&gt; property it used to toggle production flag.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed in version 15
&lt;/h2&gt;

&lt;p&gt;Last major release of Angular leverages a different system to toggle production flag: it lets &lt;code&gt;optimization&lt;/code&gt; builder option, by default passed to &lt;code&gt;production&lt;/code&gt; build target, set global &lt;code&gt;NgDevMode&lt;/code&gt; to false, without having to parse any env file.&lt;/p&gt;

&lt;p&gt;This change took off the only reason to have any environment file in the beginning, leading devs to get rid of them completely and obviously removing default &lt;code&gt;fileReplacements&lt;/code&gt; occurrences in build targets configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why people are freaking out
&lt;/h2&gt;

&lt;p&gt;Looking at what we read so far, it looks like this new approach is not something that should affect majority of Angular applications developers, being it more an "internal" of the framework.&lt;br&gt;
Thing is that, being these files already generated at project creation and correctly managed on a build target basis, it became common practice using them to store a bunch of values that need to be switched between production and development build.&lt;br&gt;
Usually these involved address of API servers to contact and Auth providers configurations.&lt;/p&gt;

&lt;p&gt;Without finding the files where expected on newly generated projects, people who never had been interested in understanding how they ever worked didn't know where to put these data, unaware of the simplicity of manually reproducing the original setup.&lt;/p&gt;
&lt;h2&gt;
  
  
  Lazy solution
&lt;/h2&gt;

&lt;p&gt;After the huge amount of complaints about this, Angular devs choose to "restore" on demand something similar to the old behaviour in &lt;a href="https://github.com/angular/angular-cli/pull/24409" rel="noopener noreferrer"&gt;15.1 release&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, from that version onwards, having environment files in place after creating a project is as simple as issuing&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng generate environments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;that as &lt;a href="https://angular.io/guide/build#configure-environment-specific-defaults" rel="noopener noreferrer"&gt;explained in docs&lt;/a&gt; will create them and configure &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;server&lt;/code&gt; targets to use them.&lt;/p&gt;

&lt;p&gt;In short: it will create &lt;code&gt;src/environments/environment.ts&lt;/code&gt; and &lt;code&gt;src/environments/environment.development.ts&lt;/code&gt; adding the latter as replacement of the former for build configuration's &lt;code&gt;development&lt;/code&gt; target&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"development"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"fileReplacements"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"replace"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/environments/environment.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"with"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/environments/environment.development.ts"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why they didn't think of that before
&lt;/h2&gt;

&lt;p&gt;The habit of putting environment variables inside those files is less straightforward than it could seem.&lt;br&gt;
Even if their name and their use could lead to look at them as the ideal spot for such information, in real case scenario they're far from best solution.&lt;br&gt;
Data like domains, endpoints, ports and alike are not bound only to &lt;em&gt;building&lt;/em&gt; target, but often more tightly to &lt;strong&gt;deployment context&lt;/strong&gt;.&lt;br&gt;
That's why many people prefer to keep them outside of building process, and let the app evaluating them at runtime as token injected at deploying, maybe as environment variable of the hosting framework or docker bundling, read by a minimal server side process and exposed as API, or even passing them in dedicated configuration file inserted as assets by pipeline, as explained in this &lt;a href="https://dev.to/thisdotmedia/runtime-environment-configuration-with-angular-4f5j"&gt;awesome article&lt;/a&gt; from good ol' &lt;a class="mentioned-user" href="https://dev.to/frederikprijck"&gt;@frederikprijck&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Now it should be clear there's been no change in environment variables management by Angular, just an upgrade that made an old easy convenient configuration not needed anymore, leading to reconsider what had always been an habit that often was a suboptimal solution, but that's available as it always has been.&lt;/p&gt;

&lt;p&gt;Cheers.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>devops</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Nx Module Federation bad Angular routing</title>
      <dc:creator>Gianpiero Errigo</dc:creator>
      <pubDate>Sun, 22 Jan 2023 12:37:33 +0000</pubDate>
      <link>https://dev.to/playfulprogramming-angular/nx-module-federation-bad-angular-routing-1ac9</link>
      <guid>https://dev.to/playfulprogramming-angular/nx-module-federation-bad-angular-routing-1ac9</guid>
      <description>&lt;p&gt;While puzzling around with Nx' Webpack Module Federation support, I stumbled upon an issue that strangely looks like none cared about before.&lt;br&gt;
I'm talking about duplication of remote component in presence of a &lt;code&gt;&amp;lt;router-outlet&amp;gt;&lt;/code&gt; in its template, when served as independent app.&lt;br&gt;
Its poor traction could be due to the fact the bug shows up only using an Angular Standalone Components setup, at least for remotes.&lt;/p&gt;


&lt;h2&gt;
  
  
  The issue
&lt;/h2&gt;

&lt;p&gt;I will take for granted the creation of a Module Federated Angular app &lt;a href="https://nx.dev/recipes/module-federation/dynamic-module-federation-with-angular" rel="noopener noreferrer"&gt;under Nx&lt;/a&gt;.&lt;br&gt;
After scaffolding, we should have an &lt;code&gt;host&lt;/code&gt; app acting as &lt;strong&gt;shell&lt;/strong&gt; of our multi-module project, and at least one &lt;code&gt;remote&lt;/code&gt; app.&lt;br&gt;
Both of them are Micro-Frontends, meaning they are capable of running on their own, even the remote one.&lt;br&gt;
That comes clear issuing &lt;code&gt;nx serve host_project_name&lt;/code&gt;, where they will be served independently, giving you the chance to look at their behaviour both when remote is accessed as child route of the host, both when it's booted as standalone app.&lt;/p&gt;

&lt;p&gt;To make thing barely functional, our host app consists of a single dumb component with two lines template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testapp-root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
             &amp;lt;a routerLink="remote_app"&amp;gt;Remote&amp;lt;/a&amp;gt;
             &amp;lt;router-outlet&amp;gt;&amp;lt;/router-outlet&amp;gt;
            `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RemoteEntryComponent&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Just an anchor linking to the remote, and a &lt;code&gt;router-outlet&lt;/code&gt; under which the child will be rendered.&lt;/p&gt;

&lt;p&gt;Similarly, the remote will be just a visual aid to show our issue&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testapp-remote1-entry&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
              &amp;lt;div style="background-color: blue; height: 100px; width: 100px; margin: 5px"&amp;gt;&amp;lt;/div&amp;gt;
            `&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RemoteEntryComponent&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here we got merely a square div coloured in blue.&lt;/p&gt;

&lt;p&gt;That's it.&lt;br&gt;
Let's look at what gets served, then.&lt;br&gt;
For our &lt;code&gt;host&lt;/code&gt; app we'll get just the link, that once clicked will route to the remote, that will appear right under it (and under &lt;code&gt;host&lt;/code&gt;'s &lt;code&gt;&amp;lt;router-outlet&amp;gt;&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5d0q8pr66w515gz7abpn.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5d0q8pr66w515gz7abpn.gif" alt="working_host" width="502" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we browse to the standalone remote served app, by default reachable at &lt;em&gt;host_port&lt;/em&gt;+1, thus on &lt;code&gt;http://localhost:4201&lt;/code&gt; for a classic setup, we'll see our remote content, the blue square, immediately rendered and no host's anchor element, as expected.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmsizjpz0opro11b5hwh8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmsizjpz0opro11b5hwh8.gif" alt="working_remote" width="502" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, where's the problem?&lt;br&gt;
The issue we're talking about arises if we add a &lt;code&gt;&amp;lt;router-outlet&amp;gt;&lt;/code&gt; element to our &lt;em&gt;remote&lt;/em&gt;.&lt;br&gt;
This is quite a common situation: many times our microfrontend will have its own internal routing, with child paths and obviously a &lt;code&gt;router-outlet&lt;/code&gt; under which rendering them.&lt;br&gt;
This is our modified remote&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testapp-remote1-entry&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
              &amp;lt;div style="background-color: blue; height: 100px; width: 100px; margin: 5px"&amp;gt;&amp;lt;/div&amp;gt;
              &amp;lt;router-outlet&amp;gt;
            `&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RemoteEntryComponent&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In this short GIF we can see how it still works flawlessy when rendered as child of our &lt;code&gt;host&lt;/code&gt; app, while acting really strangely when browsing to its standalone serving:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7wmpghl3h71abmnntiqd.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7wmpghl3h71abmnntiqd.gif" alt="doubled_remote" width="502" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our remote is rendered twice!&lt;/p&gt;


&lt;h2&gt;
  
  
  The reason
&lt;/h2&gt;

&lt;p&gt;To understand the reason behind this wrong behaviour, we got to dive a little deep into tech used by &lt;strong&gt;Nx&lt;/strong&gt; plugins to manage &lt;strong&gt;Webpack Module Federation&lt;/strong&gt; for Angular apps.&lt;br&gt;
For the &lt;code&gt;host&lt;/code&gt; app there's nothing too fancy: it gets served as standalone, and if needed is able to load external modules through a little twist of normal routing:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;remote_app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;loadRemoteModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rem1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Routes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remoteRoutes&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;See how as callback of Angular Router's &lt;code&gt;loadChildren&lt;/code&gt;, instead of classic &lt;code&gt;import(path/to/lazy_loaded.module)&lt;/code&gt; we got a call to &lt;strong&gt;Nx&lt;/strong&gt; provided  &lt;code&gt;loadRemoteModule('remote_module_name', './exposed_routes_path')&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Inside our remote's &lt;code&gt;module-federation.config.js&lt;/code&gt; there's the mapping for arguments passed to that call:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rem1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;exposes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Routes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apps/rem1/src/app/remote-entry/entry.routes.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So: the &lt;code&gt;host&lt;/code&gt;'s Router will look inside &lt;code&gt;remote&lt;/code&gt;'s &lt;code&gt;entry.route.ts&lt;/code&gt; to know which child routes it could render.&lt;br&gt;
This is default generated &lt;code&gt;entry.route.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;remoteRoutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RemoteEntryComponent&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;As we could imagine, there's just a root path &lt;code&gt;''&lt;/code&gt; pointing to default &lt;code&gt;remote&lt;/code&gt;'s root component, commonly referred as &lt;em&gt;entry component&lt;/em&gt;.&lt;br&gt;
This is nice for a situation where our &lt;code&gt;remote&lt;/code&gt; is treated as accessory module of a main app.&lt;br&gt;
All its structure is just a lazy-loaded branch inside &lt;code&gt;host&lt;/code&gt; routing tree.&lt;/p&gt;

&lt;p&gt;Things drastically change when our &lt;code&gt;remote&lt;/code&gt; has to be served as an independent app.&lt;br&gt;
Without a "parent" app already up and running, it needs to be bootstrapped as any other Angular application.&lt;br&gt;
The flow &lt;strong&gt;Nx&lt;/strong&gt; relies on starts with the usual serving of an &lt;code&gt;index.html&lt;/code&gt; built upon a template like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;testapp-remote1-entry&amp;gt;&amp;lt;/testapp-remote1-entry&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In place of &lt;strong&gt;Angular-cli&lt;/strong&gt; generated &lt;code&gt;&amp;lt;app-root&amp;gt;&amp;lt;/app-root&amp;gt;&lt;/code&gt; selector assigned to &lt;code&gt;AppComponent&lt;/code&gt;, &lt;code&gt;body&lt;/code&gt; has been populated with our custom remote entry component's selector.&lt;br&gt;
The code then sources &lt;code&gt;main.ts&lt;/code&gt; as always, that delegates to &lt;code&gt;bootstrap.ts&lt;/code&gt; file.&lt;br&gt;
Here takes place the actual application bootstrapping, that for an &lt;a href="https://angular.io/guide/standalone-components" rel="noopener noreferrer"&gt;Angular Standalone Components setup&lt;/a&gt; (concept unrelated to &lt;em&gt;standalone&lt;/em&gt; serving of our remote, don't get confused) could be enough something like:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;bootstrapApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;RemoteEntryComponent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Nx&lt;/strong&gt; remotes generator takes one step further providing to our Router eventual inner routes defined for this remote:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;appRoutes&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app/app.routes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;bootstrapApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;RemoteEntryComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;importProvidersFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;RouterModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;appRoutes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;initialNavigation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;enabledBlocking&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This &lt;code&gt;./app/app.routes&lt;/code&gt; simply lazy loads the same &lt;code&gt;entry.routes&lt;/code&gt; file exposed to our &lt;code&gt;host&lt;/code&gt; app.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;appRoutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./remote-entry/entry.routes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remoteRoutes&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And here comes the problem!&lt;br&gt;
We've already seen that file provides a route to root path &lt;code&gt;''&lt;/code&gt; rendering the root component of our remote.&lt;br&gt;
But in our remote independent serving that component is already rendered due to its reference inside remote's &lt;code&gt;index.html&lt;/code&gt; template.&lt;br&gt;
This graph should be explanatory enough:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3906ivqqlznn9mvfd6x8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3906ivqqlznn9mvfd6x8.png" alt="entry_rendering_graph" width="800" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As the purple highlighted labels emphasize, the path to rendering of the entry component for independent remote serving encounters &lt;strong&gt;two different&lt;/strong&gt; locations asking for it.&lt;br&gt;
That entry component is actually both &lt;strong&gt;declared&lt;/strong&gt; both &lt;strong&gt;routed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Why the issue doesn't occur with old NgModule-based remotes setup instead of standalone components?&lt;/strong&gt;
  &lt;blockquote&gt;
&lt;p&gt;Because &lt;strong&gt;Nx&lt;/strong&gt; remotes generator for classic ng-modular setup doesn't need to declare the entry component inside &lt;code&gt;index.html&lt;/code&gt;.&lt;br&gt;
It declares a separate root component (&lt;code&gt;AppComponent&lt;/code&gt;) hosting a &lt;code&gt;&amp;lt;router-outlet&amp;gt;&lt;/code&gt; and imports &lt;code&gt;RouterModule&lt;/code&gt; inside root module (&lt;code&gt;AppModule&lt;/code&gt;).&lt;br&gt;
This way the same route referring to entry component will be correctly rendered just once both for &lt;em&gt;Shell&lt;/em&gt; setup than for independent remote serving.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;/p&gt;



&lt;h2&gt;
  
  
  My solution
&lt;/h2&gt;

&lt;p&gt;The problem can be probably solved in many ways, since every sane solution involves a partial rewriting of &lt;strong&gt;Nx&lt;/strong&gt; generators for &lt;em&gt;remotes&lt;/em&gt; built upon &lt;em&gt;Angular standalone components&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Mi idea is to distinguish the purpose of &lt;code&gt;remote&lt;/code&gt;'s &lt;code&gt;app.routes&lt;/code&gt; and &lt;code&gt;entry.routes&lt;/code&gt;.&lt;br&gt;
At the moment the former simply lazyloads the second, leading to an identical initial routing flow for both serving contexts.&lt;br&gt;
Instead I thought of turning &lt;code&gt;app.routes&lt;/code&gt; into the real route provider for &lt;code&gt;remote&lt;/code&gt;, and leaving &lt;code&gt;entry.routes&lt;/code&gt; just as a "plugin" invoked only in &lt;em&gt;Shell&lt;/em&gt; serving context, keeping needed root path pointing to entry component, and importing &lt;code&gt;app.routes&lt;/code&gt; to use defined routes as its children.&lt;/p&gt;

&lt;p&gt;To do this, first we modify &lt;code&gt;app.routes&lt;/code&gt;, removing its &lt;code&gt;entry.routes&lt;/code&gt; lazy load, and adding our &lt;code&gt;remote&lt;/code&gt; children routes to its array.&lt;br&gt;
To keep &lt;code&gt;entry.routes&lt;/code&gt; inside our compilation unit we move its &lt;code&gt;import&lt;/code&gt; outside of routes definition, so it will be still compiled and exposed by our federation configuration, but ignored by our router during independent serving:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* commented-out original default entry.routes import 
export const appRoutes: Route[] = [
  {
    path: '',
    loadChildren: () =&amp;gt;
      import('./remote-entry/entry.routes').then((m) =&amp;gt; m.remoteRoutes),
  },
]; */&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./remote-entry/entry.routes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;appRoutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;first_child_route&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FirstChildRouteComponent&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;second_child_route&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SecondChildRouteComponent&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;third_child_route&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ThirdChildRouteComponent&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; 
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now we can edit &lt;code&gt;entry.routes&lt;/code&gt;, enriching its only route with an array of children, simply importing the one defined in &lt;code&gt;app.routes&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;appRoutes&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../app.routes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RemoteEntryComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./entry.component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;remoteRoutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RemoteEntryComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;appRoutes&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In the end we can appreciate the result of our efforts, looking at our blue square rendered a single time for any serving methodology:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2nsgdhy14iszeptbz6mw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2nsgdhy14iszeptbz6mw.gif" alt="fixed_remote" width="502" height="291"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;I think &lt;strong&gt;Nx&lt;/strong&gt; support for Angular standalone components federation is still a bit "unripe".&lt;br&gt;
I found a couple oddities in its implementation I'll spend some words about in a future article, maybe.&lt;br&gt;
It does a great job though, raising the coder from writing a lot of boilerplate and, considering I'm not exactly an expert in this field, there's the chance some of the things looking like "flaws" to me, were real solutions for cornercases or common use scenarios I didn't think of.&lt;br&gt;
For the very same reason, the one I presented as a "solution" could be sub-optimal if not even wrong for other situations.&lt;br&gt;
I didn't test it extensively, that's why as usual you're highly encouraged to leave a comment if anything doesn't sound right.&lt;/p&gt;

&lt;p&gt;Anyway, I opened a ticket for this specific bug, and issued a PR with my suggested solution:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/nrwl/nx/issues/14551" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Duplicate entry component rendering for standalone ng component served as independent frontend
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#14551&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/4javier" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F459381%3Fv%3D4" alt="4javier avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/4javier" rel="noopener noreferrer"&gt;4javier&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/nrwl/nx/issues/14551" rel="noopener noreferrer"&gt;&lt;time&gt;Jan 23, 2023&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Current Behavior&lt;/h3&gt;
&lt;p&gt;When generating angular standalone component as remote, the entry component is listed inside &lt;code&gt;entry.routes&lt;/code&gt; for root path &lt;code&gt;''&lt;/code&gt;.
That's fine when module is lazy loaded by shell app, but gives a problem when served as independent microfrontend.
In that case the entry component is declared into &lt;code&gt;index.html&lt;/code&gt; too, so if a &lt;code&gt;router-outlet&lt;/code&gt; gets added somewhere in the tree, the component will be rendered twice.&lt;/p&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Expected Behavior&lt;/h3&gt;
&lt;p&gt;When served as independent app, entry.routes should be ignored, and inner routes should be defined into remote's &lt;code&gt;app.routes&lt;/code&gt; directly.&lt;/p&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Github Repo&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://github.com/4javier/monotest" rel="noopener noreferrer"&gt;https://github.com/4javier/monotest&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Steps to Reproduce&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;nx serve shell&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;on &lt;code&gt;localhost:4200&lt;/code&gt; click on "remote" link: a blue square is rendered&lt;/li&gt;
&lt;li&gt;on &lt;code&gt;localhost:4201&lt;/code&gt;: two squares get rendered&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Nx Report&lt;/h3&gt;
&lt;div class="highlight highlight-source-shell js-code-highlight"&gt;
&lt;pre&gt;Node &lt;span class="pl-c1"&gt;:&lt;/span&gt; 14.20.0
   OS   &lt;span class="pl-c1"&gt;:&lt;/span&gt; linux x64
   npm  &lt;span class="pl-c1"&gt;:&lt;/span&gt; 6.14.17
   
   nx &lt;span class="pl-c1"&gt;:&lt;/span&gt; 15.5.1
   @nrwl/angular &lt;span class="pl-c1"&gt;:&lt;/span&gt; 15.5.1
   @nrwl/cypress &lt;span class="pl-c1"&gt;:&lt;/span&gt; 15.5.1
   @nrwl/detox &lt;span class="pl-c1"&gt;:&lt;/span&gt; Not Found
   @nrwl/devkit &lt;span class="pl-c1"&gt;:&lt;/span&gt; 15.5.1
   @nrwl/esbuild &lt;span class="pl-c1"&gt;:&lt;/span&gt; Not Found
   @nrwl/eslint-plugin-nx &lt;span class="pl-c1"&gt;:&lt;/span&gt; 15.5.1
   @nrwl/expo &lt;span class="pl-c1"&gt;:&lt;/span&gt; Not Found
   @nrwl/express &lt;span class="pl-c1"&gt;:&lt;/span&gt; Not Found
   @nrwl/jest &lt;span class="pl-c1"&gt;:&lt;/span&gt; 15.5.1
   @nrwl/js &lt;span class="pl-c1"&gt;:&lt;/span&gt; 15.5.1
   @nrwl/linter &lt;span class="pl-c1"&gt;:&lt;/span&gt; 15.5.1
   @nrwl/nest &lt;span class="pl-c1"&gt;:&lt;/span&gt; Not Found
   @nrwl/next &lt;span class="pl-c1"&gt;:&lt;/span&gt; Not Found
   @nrwl/node &lt;span class="pl-c1"&gt;:&lt;/span&gt; Not Found
   @nrwl/nx-cloud &lt;span class="pl-c1"&gt;:&lt;/span&gt; Not Found
   @nrwl/nx-plugin &lt;span class="pl-c1"&gt;:&lt;/span&gt; Not Found
   @nrwl/react &lt;span class="pl-c1"&gt;:&lt;/span&gt; Not Found
   @nrwl/react-native &lt;span class="pl-c1"&gt;:&lt;/span&gt; Not Found
   @nrwl/rollup &lt;span class="pl-c1"&gt;:&lt;/span&gt; Not Found
   @nrwl/schematics &lt;span class="pl-c1"&gt;:&lt;/span&gt; Not Found
   @nrwl/storybook &lt;span class="pl-c1"&gt;:&lt;/span&gt; Not Found
   @nrwl/web &lt;span class="pl-c1"&gt;:&lt;/span&gt; Not Found
   @nrwl/webpack &lt;span class="pl-c1"&gt;:&lt;/span&gt; 15.5.1
   @nrwl/workspace &lt;span class="pl-c1"&gt;:&lt;/span&gt; 15.5.1
   @nrwl/vite &lt;span class="pl-c1"&gt;:&lt;/span&gt; Not Found
   typescript &lt;span class="pl-c1"&gt;:&lt;/span&gt; 4.8.4
   ---------------------------------------
   Local workspace plugins:
   ---------------------------------------
   Community plugins:&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Failure Logs&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;No response&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Additional Information&lt;/h3&gt;
&lt;p&gt;I explained extensively the issue and my suggested solution here.
&lt;a href="https://dev.to/this-is-angular/nx-module-federation-bad-angular-routing-1ac9" rel="nofollow"&gt;https://dev.to/this-is-angular/nx-module-federation-bad-angular-routing-1ac9&lt;/a&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nrwl/nx/issues/14551" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Cheers.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>nx</category>
      <category>typescript</category>
      <category>webpack</category>
    </item>
    <item>
      <title>Material forms: mat-checkbox disabling controls</title>
      <dc:creator>Gianpiero Errigo</dc:creator>
      <pubDate>Thu, 12 Jan 2023 10:55:51 +0000</pubDate>
      <link>https://dev.to/playfulprogramming-angular/material-forms-mat-checkbox-disabling-controls-2jc6</link>
      <guid>https://dev.to/playfulprogramming-angular/material-forms-mat-checkbox-disabling-controls-2jc6</guid>
      <description>&lt;p&gt;In previous article we analyzed a generic workflow for the creation of a directive capable of adding a native checkbox element to a basic form in pure good-old HTML.&lt;br&gt;
Now we'll try to replicate the idea on a more realistic usecase involving some common &lt;a href="https://material.angular.io/components/categories" rel="noopener noreferrer"&gt;Angular Material Components&lt;/a&gt; often used in forms composition.&lt;br&gt;
Here pitfalls and tradeoffs will be more evident and will probably make you questioning once more if a global directive of this kind is a convenient solution.&lt;/p&gt;


&lt;h2&gt;
  
  
  Recap our goals
&lt;/h2&gt;

&lt;p&gt;After reading first article of the series, it should be clear which features our checkbox should provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reflect initial enabling status of bound control
at start&lt;/li&gt;
&lt;li&gt;switch that status on click&lt;/li&gt;
&lt;li&gt;listen to any control status changing issued programmatically and modify its own state accordingly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This time we will setup a more realistic harness, a common structure for a really simple form:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;code&gt;flex-direction: column&lt;/code&gt; flexbox container to vertically host our controls one-per-line&lt;/li&gt;
&lt;li&gt;material elements wrapping our native controls

&lt;ul&gt;
&lt;li&gt;we will notice how Material makes extensive use of content projection, often flooding DOM tree beyond any expectation&lt;/li&gt;
&lt;li&gt;we will consider to leverage some nice properties these wrapping components expose&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;to be consistent with Material Design, our plain HTML &lt;code&gt;&amp;lt;input type="checkbox"&amp;gt;&lt;/code&gt; will be replaced by its glorified Material version &lt;a href="https://material.angular.io/components/checkbox/overview" rel="noopener noreferrer"&gt;mat-checkbox&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our Angular Material reference version will be the new one (15.x) based on &lt;a href="https://github.com/material-components/material-components-web" rel="noopener noreferrer"&gt;Material Design Components for Web (MDC)&lt;/a&gt;.&lt;br&gt;
Its API shouldn't be too different than previous versions, though.&lt;/p&gt;

&lt;p&gt;This second version of our directive will get the selector: &lt;code&gt;selectableMat&lt;/code&gt;, while we'll recycle the old model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;plainForm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormGroup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;radio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;range&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;singleSel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;multiSel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;([]),&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and here its template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt; &lt;span class="na"&gt;[formGroup]=&lt;/span&gt;&lt;span class="s"&gt;"plainForm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;mat-form-field&lt;/span&gt; &lt;span class="na"&gt;selectableMat&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;mat-label&amp;gt;&lt;/span&gt;A text control&lt;span class="nt"&gt;&amp;lt;/mat-label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;matInput&lt;/span&gt; &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/mat-form-field&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;mat-form-field&lt;/span&gt; &lt;span class="na"&gt;selectableMat&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;mat-label&amp;gt;&lt;/span&gt;A number control&lt;span class="nt"&gt;&amp;lt;/mat-label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;matInput&lt;/span&gt; &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"number"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"number"&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/mat-form-field&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;A radio control&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;mat-radio-group&lt;/span&gt; &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"radio"&lt;/span&gt; &lt;span class="na"&gt;selectableMat&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;mat-radio-button&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"yes"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Yes&lt;span class="nt"&gt;&amp;lt;/mat-radio-button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;mat-radio-button&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"no"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;No&lt;span class="nt"&gt;&amp;lt;/mat-radio-button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/mat-radio-group&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;A range control&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;mat-slider&lt;/span&gt; &lt;span class="na"&gt;selectableMat&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"range"&lt;/span&gt; &lt;span class="na"&gt;matSliderThumb&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/mat-slider&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;mat-form-field&lt;/span&gt; &lt;span class="na"&gt;selectableMat&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;mat-label&amp;gt;&lt;/span&gt;A single selection control&lt;span class="nt"&gt;&amp;lt;/mat-label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;mat-select&lt;/span&gt; &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"singleSel"&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;mat-option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;--Please choose an option--&lt;span class="nt"&gt;&amp;lt;/mat-option&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;mat-option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"dog"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Dog&lt;span class="nt"&gt;&amp;lt;/mat-option&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;mat-option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"cat"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Cat&lt;span class="nt"&gt;&amp;lt;/mat-option&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;mat-option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"hamster"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hamster&lt;span class="nt"&gt;&amp;lt;/mat-option&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/mat-select&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/mat-form-field&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;mat-form-field&lt;/span&gt; &lt;span class="na"&gt;selectableMat&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;mat-label&amp;gt;&lt;/span&gt;A multiple selection control&lt;span class="nt"&gt;&amp;lt;/mat-label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;mat-select&lt;/span&gt; &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"multiSel"&lt;/span&gt; &lt;span class="na"&gt;multiple&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;mat-option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;--Please choose multiple options--&lt;span class="nt"&gt;&amp;lt;/mat-option&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;mat-option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"dog"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Dog&lt;span class="nt"&gt;&amp;lt;/mat-option&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;mat-option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"cat"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Cat&lt;span class="nt"&gt;&amp;lt;/mat-option&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;mat-option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"hamster"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hamster&lt;span class="nt"&gt;&amp;lt;/mat-option&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/mat-select&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/mat-form-field&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;(click)=&lt;/span&gt;&lt;span class="s"&gt;"showSubmitObject()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't worry, we're gonna examine every control one by one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Replacing plain checkbox with fancy &lt;code&gt;mat-checkbox&lt;/code&gt;: nice, but...
&lt;/h2&gt;

&lt;p&gt;We already said that, being in a Material environment, we want to replace our plain old browser-styled checkbox with a &lt;em&gt;posh&lt;/em&gt; &lt;code&gt;MatCheckbox&lt;/code&gt; component.&lt;br&gt;
Sounds good, but there's a problem: &lt;code&gt;mat-checkbox&lt;/code&gt; is not a registered element, thus our &lt;em&gt;Renderer2&lt;/em&gt; cannot call &lt;em&gt;WEBApi's Document&lt;/em&gt; interface to create it.&lt;br&gt;
We got to dynamically generate it as a component in the Angular way.&lt;br&gt;
This means that our directive will have to get a reference of its host element's &lt;em&gt;ViewContainer&lt;/em&gt;, and append inside it the newly generated checkbox &lt;em&gt;View&lt;/em&gt;.&lt;br&gt;
It's way easier than it sounds, and we can see it in action in the early lines of our directive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;disablingCheckbox&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ComponentRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MatCheckbox&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;vcr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ViewContainerRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disablingCheckbox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vcr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MatCheckbox&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We declare a property typed as a &lt;em&gt;ComponentRef&lt;/em&gt; generated by a &lt;em&gt;factory&lt;/em&gt; of &lt;em&gt;MatCheckbox&lt;/em&gt; components to have access to its properties later, inject in constructor the &lt;em&gt;ViewContainerRef&lt;/em&gt; of the element to which the directive has been applied, and then create an instance of the component through &lt;code&gt;ViewContainerRef.createComponent&lt;/code&gt;, without passing any &lt;em&gt;index&lt;/em&gt; argument, so that the method will append it as &lt;em&gt;ViewContainer&lt;/em&gt;'s last child.&lt;/p&gt;

&lt;p&gt;Here we got to stop a second and do some considerations: since we need to access the host's &lt;em&gt;ViewContainerRef&lt;/em&gt;, we got to carefully ponder over the element on which applying our directive selector, because it will condition not only the tokens we can access without querying, but the &lt;em&gt;View&lt;/em&gt; after which the &lt;code&gt;MatCheckbox&lt;/code&gt; will be rendered, too.&lt;br&gt;
Let's try to explain with an example, involving a mat-form-field:&lt;br&gt;
If we were applying our directive to the inner &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;mat-form-field&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;mat-label&amp;gt;&lt;/span&gt;A text control&lt;span class="nt"&gt;&amp;lt;/mat-label&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;matInput&lt;/span&gt; &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;selectableMat&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/mat-form-field&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we would have been able to inject &lt;code&gt;NgControl&lt;/code&gt; directly in constructor, but our &lt;code&gt;&amp;lt;mat-checkbox&amp;gt;&lt;/code&gt; would have been rendered as last child of &lt;code&gt;&amp;lt;mat-form-field&amp;gt;&lt;/code&gt;, inheriting its styling and state.&lt;br&gt;
&lt;code&gt;&amp;lt;mat-form-field&amp;gt;&lt;/code&gt; wrap its children inside a &lt;code&gt;flex-direction: column&lt;/code&gt; flexbox container, so our checkbox will be placed &lt;strong&gt;below&lt;/strong&gt; its last child.&lt;br&gt;
Imagine if we had chosen an horizontal layout, using &lt;code&gt;flex-direction: row&lt;/code&gt; for our main container: we would have expected to get our checkbox rendered &lt;strong&gt;beside&lt;/strong&gt; the form field&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmt7ng8kqraaq5xr8g38g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmt7ng8kqraaq5xr8g38g.png" alt="side checkbox" width="267" height="57"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;instead, being it child of the view that's inside &lt;code&gt;&amp;lt;mat-form-field&amp;gt;&lt;/code&gt;, it's actually part of the element and positioned below every other children of it&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbzob3cvnc3r51epcd2i3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbzob3cvnc3r51epcd2i3.png" alt="inner checkbox" width="216" height="98"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that's not even the worst problem: as a children of the very same element it's in charge to disable, when unchecked it will inherit the &lt;code&gt;disabled&lt;/code&gt; state from its parent, starting a chain with unpredictable consequences (the better, letting the binding &lt;em&gt;form-field &amp;amp; checkbox&lt;/em&gt; in an inconsistent state).&lt;/p&gt;

&lt;p&gt;That's why we prefer to apply our directive directly on the wrapper element,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;mat-form-field&lt;/span&gt; &lt;span class="na"&gt;selectableMat&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;mat-label&amp;gt;&lt;/span&gt;A text control&lt;span class="nt"&gt;&amp;lt;/mat-label&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;matInput&lt;/span&gt; &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/mat-form-field&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;this way our checkbox will be placed inside that element's &lt;em&gt;ViewContainer&lt;/em&gt;, and not inside element itself, following the layout we defined for its container, and not receiving any state or event from the control it's commanding.&lt;br&gt;
For our vertical layout this will be the result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy85ivpag26xdqopl6enk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy85ivpag26xdqopl6enk.png" alt="below checkbox" width="216" height="114"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our requirement could easily be a vertical layout but with the checkbox placed &lt;strong&gt;beside&lt;/strong&gt; related control.&lt;br&gt;
Unfortunately there's not a clean way to instruct a directive to do that, and the best solution would be forcing the user to put every single material control wrapper element inside a parent one, on which applying our directive to style that per our needs.&lt;br&gt;
This would defeat the basic idea of a general purpose directive acting on DOM structure: at that point I'm more in favor of one limiting its functionalities to the model, to be applied to a checkbox placed and styled by the user manually in template&lt;/p&gt;
&lt;h2&gt;
  
  
  How it should be: &lt;code&gt;&amp;lt;mat-form-field&amp;gt;&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;For most common elements available in a form, &lt;code&gt;select&lt;/code&gt;s and text-like &lt;code&gt;input&lt;/code&gt;s, both &lt;em&gt;native&lt;/em&gt; both in &lt;em&gt;Material&lt;/em&gt; variants,  Angular Material allows the use of the wrapper &lt;a href="https://material.angular.io/components/form-field/overview" rel="noopener noreferrer"&gt;mat-form-field&lt;/a&gt;. &lt;br&gt;
We will not spend time explaining all the structural and styling modifications it applies to wrapped control, but will focus on some property it exposes, and that &lt;em&gt;apparently&lt;/em&gt; could be of interest for the functionalities of our directive.&lt;br&gt;
Anyway, to understand the complexity of the DOM manipulation Material applies, look at how this basic template&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;mat-form-field&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;mat-label&amp;gt;&lt;/span&gt;A text control&lt;span class="nt"&gt;&amp;lt;/mat-label&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;matInput&lt;/span&gt; &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;flourishes in this branch after rendering &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5t3ptld00d1dlje9ge9l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5t3ptld00d1dlje9ge9l.png" alt="material form mess" width="745" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Back to the API it exposes, most important class is &lt;code&gt;MatFormFieldControl&lt;/code&gt;, provided by all supported control elements: for native &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt; through the application of &lt;code&gt;matInput&lt;/code&gt; directive, and automatically by &lt;code&gt;&amp;lt;mat-select&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;mat-chip-list&amp;gt;&lt;/code&gt;.&lt;br&gt;
Among its properties one in particular catches our interest: &lt;code&gt;disabled&lt;/code&gt;.&lt;br&gt;
It could serve our project, if only looking at its code we wouldn't realize that&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it's a readonly property: thus it's supposed to be accessed just to check status of the control, and not as a setter&lt;/li&gt;
&lt;li&gt;it's a plain &lt;code&gt;boolean&lt;/code&gt;, not a reactive property like an &lt;code&gt;Observable&amp;lt;boolean&amp;gt;&lt;/code&gt;, so it cannot be listen to on its own to get live status of the control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One looking more promising is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;ngControl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NgControl&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;AbstractControlDirective&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're familiar with &lt;code&gt;NgControl&lt;/code&gt;, we used it in our plain HTML example, and it offers all we need.&lt;br&gt;
Its union type is due to &lt;code&gt;MatFormFieldControl&lt;/code&gt; being assignable to controls that can be nullable, and to &lt;code&gt;FormGroup&lt;/code&gt; and &lt;code&gt;FormaArray&lt;/code&gt; too, that extend &lt;code&gt;AbstractControlDirective&lt;/code&gt; through their common ancestor &lt;code&gt;ControlContainer&lt;/code&gt;, but not its subclass &lt;code&gt;NgControl&lt;/code&gt;. &lt;br&gt;
That's actually not a big problem, considering properties interesting for our usecase are part of the parent class.&lt;br&gt;
Anyway, typings could be a little annoying, considering that &lt;code&gt;MatFormFieldControl&lt;/code&gt; is obviously generic, so we should specify its type at injection time other than managing union type of returned value.&lt;br&gt;
So: save ourself a bit of type-narrowing confusion, and access our &lt;code&gt;NgControl&lt;/code&gt; the old way, simply querying for it in our projected content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ContentChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;NgControl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NgControl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing different than what &lt;code&gt;MatFormField&lt;/code&gt; does &lt;a href="https://github.com/angular/components/blob/main/src/material/form-field/form-field.ts#L168" rel="noopener noreferrer"&gt;in its code&lt;/a&gt;, so even the lifecycle access constraint will be identical.&lt;/p&gt;

&lt;p&gt;Having retrieved it as &lt;code&gt;@ContentChild&lt;/code&gt; we got to put our logic inside &lt;code&gt;ngAfterContentInit()&lt;/code&gt;, where it will result defined&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;ngAfterContentInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disablingCheckbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checked&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;enable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;disable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We leverage &lt;code&gt;@Output() change: EventEmitter&amp;lt;E&amp;gt;&lt;/code&gt; from &lt;code&gt;MatCheckbox&lt;/code&gt; class to react to user interactions with our checkbox and, through the &lt;code&gt;control&lt;/code&gt; property of the &lt;code&gt;NgControl&lt;/code&gt; we queried, set the status of &lt;code&gt;FormControl&lt;/code&gt; accordingly.&lt;/p&gt;

&lt;p&gt;Now, the other way of the binding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;statusChanges&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;startWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DISABLED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DISABLED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disablingCheckbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disablingCheckbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remembering from last articles that &lt;code&gt;NgControl.statusChanges&lt;/code&gt; does &lt;strong&gt;not emit for control initial status&lt;/strong&gt;, we pipe our observation to the usual &lt;code&gt;startWith&lt;/code&gt; emitting a string relatable to the real initial status of the control.&lt;br&gt;
After that, for every emission we'll call &lt;code&gt;ComponentRef.setInput&lt;/code&gt;, &lt;a href="https://angular.io/api/core/ComponentRef#setInput" rel="noopener noreferrer"&gt;introduced in Angular 14.1&lt;/a&gt;, on our &lt;em&gt;MatCheckbox&lt;/em&gt; instance, that will take care of managing change detection cycles for us, while keeping checkbox state consonant with control status.&lt;/p&gt;
&lt;h2&gt;
  
  
  Outside &lt;code&gt;&amp;lt;mat-form-field&amp;gt;&lt;/code&gt; things start to branch
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;mat-form-field&amp;gt;&lt;/code&gt; is designed to host a limited amount of controls element types as we already explained, so for &lt;code&gt;type="radio"&lt;/code&gt; and &lt;code&gt;type="range"&lt;/code&gt; in our example we need to setup something different.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://material.angular.io/components/radio/api" rel="noopener noreferrer"&gt;MatRadioGroup&lt;/a&gt; looks like &lt;em&gt;Material&lt;/em&gt; component appointed to manage radio type selectors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;mat-radio-group&lt;/span&gt; &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"radio"&lt;/span&gt; &lt;span class="na"&gt;selectableMat&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;mat-radio-button&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"yes"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Yes&lt;span class="nt"&gt;&amp;lt;/mat-radio-button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;mat-radio-button&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"no"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;No&lt;span class="nt"&gt;&amp;lt;/mat-radio-button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/mat-radio-group&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First difference we notice is that in this case &lt;code&gt;formControlName&lt;/code&gt; is applied to the top-most element together with our directive.&lt;br&gt;
&lt;code&gt;MatRadioGroup&lt;/code&gt; class is the one providing &lt;code&gt;NG_VALUE_ACCESSOR&lt;/code&gt;, and that actually makes its use a bit more sound than pure HTML example, where the same &lt;code&gt;formControlName&lt;/code&gt; binding was applied to every &lt;code&gt;&amp;lt;input type="radio"&amp;gt;&lt;/code&gt;&lt;br&gt;
This leads to the need of some changes in our approach, because with this configuration &lt;code&gt;NgControl&lt;/code&gt; cannot be queried as content, being it directly provided by the host we're targeting.&lt;/p&gt;

&lt;p&gt;We could pass an optional &lt;code&gt;NgControl&lt;/code&gt; typed argument  in constructor, or as I prefer for readability:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ContentChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;NgControl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NgControl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;_radioCtrl&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;NgControl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;vcr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ViewContainerRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ElementRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodeName&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MAT-RADIO-GROUP&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_radioCtrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;NgControl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We defined a new optional property &lt;code&gt;_radioCtrl&lt;/code&gt; typed as &lt;code&gt;NgControl&lt;/code&gt;, and inside constructor body we use &lt;code&gt;inject()&lt;/code&gt; function &lt;a href="https://angular.io/api/core/inject" rel="noopener noreferrer"&gt;introduced in Angular 14&lt;/a&gt;, to assign hosting View's &lt;code&gt;NgControl&lt;/code&gt; instance to it, only after having checked &lt;code&gt;nodeName&lt;/code&gt; property of hosting element retrieved by &lt;code&gt;ElementRef&lt;/code&gt; will match the one for &lt;code&gt;MatRadioGroup&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;ngAfterContentInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodeName&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MAT-RADIO-GROUP&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ctrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_radioCtrl&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we wanna keep a common logic no matter which type of control is exposing its &lt;code&gt;NgControl&lt;/code&gt;, we got to be sure to assign our freshly created &lt;code&gt;_radioCtrl&lt;/code&gt; to generic &lt;code&gt;ctrl&lt;/code&gt; property.&lt;br&gt;
But we cannot do this directly in constructor, otherwise it would be overwrote by &lt;code&gt;@ContentChild&lt;/code&gt; initialization, resulting in &lt;code&gt;undefined&lt;/code&gt; for &lt;code&gt;MatRadioGroup&lt;/code&gt; components (remember: for this type of control, &lt;code&gt;formControlName&lt;/code&gt; directive is applied to hosting component directly, not to its projected &lt;code&gt;&amp;lt;mat-radio-button&amp;gt;&lt;/code&gt;s).&lt;br&gt;
So we put this logic in &lt;code&gt;ngAfterContentInit()&lt;/code&gt;, and&lt;br&gt;
like we've done for its injection, we do this only after having checked hosting element nodeName.&lt;/p&gt;
&lt;h2&gt;
  
  
  The sore point: &lt;code&gt;&amp;lt;mat-slider&amp;gt;&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Last typology of input left to manage is our &lt;code&gt;type="range"&lt;/code&gt;.&lt;br&gt;
In general, this type of control doesn't get too much cheers when it shows up in a form.&lt;br&gt;
Styling is far from trivial, even for enterprise-level framework like Bootstrap or Material.&lt;br&gt;
But I got to say: Angular Material reaches a whole new level of entanglement with its &lt;a href="https://material.angular.io/components/slider/overview" rel="noopener noreferrer"&gt;mat-slider&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Maybe for the strange nature of range control itself, or for the choice to enrich its functionality adding an optional second thumb to let the user select an interval of values... its implementation is really something.&lt;br&gt;
Theoretically it should be quite a smooth operation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;mat-slider&lt;/span&gt; &lt;span class="na"&gt;selectableMat&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"range"&lt;/span&gt; &lt;span class="na"&gt;matSliderThumb&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/mat-slider&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We apply our directive to wrapping element, planning to access &lt;code&gt;NgControl&lt;/code&gt; through &lt;code&gt;@ContentChild&lt;/code&gt; like we did for &lt;code&gt;MatFormField&lt;/code&gt;.&lt;br&gt;
But we didn't reckon with &lt;code&gt;matSliderThumb&lt;/code&gt;!&lt;br&gt;
This directive has to be applied to the inner &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; element (that internally gets assigned &lt;code&gt;type="range"&lt;/code&gt;), because it registers as &lt;em&gt;ControlValueAccessor&lt;/em&gt;, giving form capabilities to its parent &lt;code&gt;MatSlider&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Yet its behaviour seems to interfere with normal change detection recognition of the input it's bound to.&lt;br&gt;
For what we've seen, our directive current implementation should deal flawlessy with this new control, because it has a structure comparable with the one of &lt;code&gt;MatFormField&lt;/code&gt;, but if we try to assign an initial &lt;code&gt;disabled&lt;/code&gt; status to our range control&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or to add a button triggering a programmatically call to its &lt;code&gt;FormControl.disable()&lt;/code&gt; method&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;(click)=&lt;/span&gt;&lt;span class="s"&gt;"disableRange()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Disable&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;disableRange&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;plainForm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;controls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we'll notice that our dedicated checkbox' state doesn't follow control status change.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F463oj40cu85av8n83jqj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F463oj40cu85av8n83jqj.png" alt="range state inconsistency" width="174" height="112"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Look at the inconsistency between disabled control but flagged checkbox.&lt;/p&gt;

&lt;p&gt;In its &lt;em&gt;setter&lt;/em&gt; role it works correctly: a first click will uncheck the box without toggling control status, and following ones will act as they're supposed to do.&lt;br&gt;
This means that the problem resides in its &lt;em&gt;listening&lt;/em&gt; role&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;statusChanges&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;startWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DISABLED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DISABLED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disablingCheckbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disablingCheckbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Debugging at runtime we can see that, unlike what happens with &lt;code&gt;MatFormField&lt;/code&gt;, even inside &lt;code&gt;ngAfterContentInit()&lt;/code&gt; the property &lt;code&gt;ctrl.control&lt;/code&gt;, that reflects the runtime status of underlying &lt;code&gt;AbstractControl&lt;/code&gt; for &lt;code&gt;NgControl&lt;/code&gt;, is still not initialized as one would expect, returning &lt;code&gt;undefined&lt;/code&gt; and missing the subscription on &lt;code&gt;statusChanges&lt;/code&gt; event emitter.&lt;/p&gt;

&lt;p&gt;The evidence we're facing a timing issue is presented by this ugly hack, where just for testing we register our subscription inside MacroTask by &lt;code&gt;setTimeout&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;statusChanges&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;startWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DISABLED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DISABLED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disablingCheckbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disablingCheckbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see, control's disabled status, be it set as initial value or asynchronously, is reflected by checkbox state&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fipk9m1ibvviio4mejytw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fipk9m1ibvviio4mejytw.png" alt="range state consistent" width="175" height="111"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the moment I didn't find any elegant solution to overcome the issue, so whoever should know better is welcome in comments as usual. 😃&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;The goal of this short series is to make people aware of difficulties they can encounter while trying to "generalize" a task that looked repetitive at the limit of copy/pasting.&lt;br&gt;
I think it's now clear that the more advanced the underlying framework for styling and model/view binding, the more challenging the task become.&lt;br&gt;
My suggestion is to always "abstract" something when this &lt;strong&gt;actually&lt;/strong&gt; represents itself a fair amount of times, and not when &lt;strong&gt;we think&lt;/strong&gt; it's something that will come again often.&lt;br&gt;
Maybe there will be another short episode of this series due to my interest in Bootstrap, but in any case, thanks for reading 'til down here.&lt;/p&gt;

</description>
      <category>hackathon</category>
      <category>discuss</category>
      <category>community</category>
    </item>
    <item>
      <title>Angular forms: checkbox disabling controls</title>
      <dc:creator>Gianpiero Errigo</dc:creator>
      <pubDate>Mon, 09 Jan 2023 10:24:47 +0000</pubDate>
      <link>https://dev.to/playfulprogramming-angular/angular-forms-checkbox-disabling-controls-29np</link>
      <guid>https://dev.to/playfulprogramming-angular/angular-forms-checkbox-disabling-controls-29np</guid>
      <description>&lt;h2&gt;
  
  
  How to write a directive to add it.
&lt;/h2&gt;

&lt;h2&gt;
  
  
  And why you shouldn't.
&lt;/h2&gt;

&lt;p&gt;If as a coder you never found yourself having wasted an unjustifiable amount of time trying to automatize a procedure, just to realize that rewriting it for the couple of times it was actually needed took 1/1000 of resources...&lt;br&gt;
&lt;strong&gt;YOU'RE A LIAR!!!&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Be honest: everyone, at least at the beginnings, fell for that trap called &lt;em&gt;premature optimization&lt;/em&gt;, &lt;a href="https://en.wikiquote.org/wiki/Donald_Knuth" rel="noopener noreferrer"&gt;the root of all evil&lt;/a&gt; perfectly summarized in this over-used xkcd strip:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz73fofihk1itwbmuq2sm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz73fofihk1itwbmuq2sm.png" title="Xkcd at it again" alt="xkcd salt long run" width="550" height="230"&gt;&lt;/a&gt;&lt;br&gt;
(I know, this is just a "nuance" of many kinds of premature optimization issue, but that's the one we're gonna talk about).&lt;/p&gt;

&lt;p&gt;What we'll be showing in this article is an example of those situations: a mildly frequent necessity involving fairly amount of modifications to DOM tree. Something that in real usecase scenarios styled with tools already complex enough on their own, will leave you with the feeling that huge pile of trade-offs and workarounds is not worth the effort.&lt;br&gt;
So, we'll use the pretense of implementing a directive adding a checkbox element to any of our form controls letting users capable of disabling them, to explore some Angular tools aiming at manipulating the project a bit over basic framework use.&lt;/p&gt;


&lt;h2&gt;
  
  
  Useless harness
&lt;/h2&gt;

&lt;p&gt;In this first article we'll use as example a pure HTML form, with plain controls without any styling, separated by native &lt;code&gt;&amp;lt;hr&amp;gt;&lt;/code&gt; tags (we're not even using a list).&lt;br&gt;
This is something you'll never encounter in everyday coding (unless you're among the lucky ones forced to work on an early '90s codebase), but will let us focus on the generic technic to be issued for our goal.&lt;/p&gt;

&lt;p&gt;On the left there's our plain form, and on the right what we wanna achieve just applying a directive to every control in our template (we could design our directive to be applied on the form itself and issuing its logic for every child control, but let's keep it even simpler).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbp422igh6pdalkwakar3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbp422igh6pdalkwakar3.jpg" alt="plain forms before after" width="600" height="420"&gt;&lt;/a&gt;&lt;br&gt;
Here we got its template&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;[formGroup]=&lt;/span&gt;&lt;span class="s"&gt;"plainForm"&lt;/span&gt; &lt;span class="na"&gt;(ngSubmit)=&lt;/span&gt;&lt;span class="s"&gt;"showSubmitObject()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;A text control&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;selectablePlain&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;hr&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;A number control&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"number"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"number"&lt;/span&gt; &lt;span class="na"&gt;selectablePlain&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;hr&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;A radio control&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"yes"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Yes&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"radio"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"radio"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"yes"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"yes"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"no"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;No&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"radio"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"radio"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"no"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"no"&lt;/span&gt; &lt;span class="na"&gt;selectablePlain&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&amp;lt;hr&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;A range control&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"range"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"range"&lt;/span&gt; &lt;span class="na"&gt;selectablePlain&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;hr&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;A single selection control&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;select&lt;/span&gt; &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"singleSel"&lt;/span&gt; &lt;span class="na"&gt;selectablePlain&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;--Please choose an option--&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"dog"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Dog&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"cat"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Cat&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"hamster"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hamster&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/select&amp;gt;&amp;lt;hr&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;A multiple selection control&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;select&lt;/span&gt; &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"multiSel"&lt;/span&gt; &lt;span class="na"&gt;multiple&lt;/span&gt; &lt;span class="na"&gt;selectablePlain&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;--Please choose multiple options--&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"dog"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Dog&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"cat"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Cat&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"hamster"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hamster&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/select&amp;gt;&amp;lt;hr&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;br&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;Submit&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can notice every control has been applied not only with the usual &lt;code&gt;formControlName&lt;/code&gt; directive binding it to relative &lt;code&gt;FormControl&lt;/code&gt; in code, but with a &lt;code&gt;selectablePlain&lt;/code&gt; too: the selector for our directive that's gonna be.&lt;br&gt;
Nothing else peculiar, I used most common types of control: text, number, radio, range, select and multi-select.&lt;br&gt;
And here's its binding code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PlainControlsComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nx"&gt;plainForm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormGroup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;radio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;range&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;singleSel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;multiSel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;([]),&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Visualize our goals
&lt;/h2&gt;

&lt;p&gt;We can separate the expected functionalities of our directive in two tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DOM manipulation&lt;/strong&gt;: it should add an &lt;code&gt;&amp;lt;input type="checkbox"&amp;gt;&lt;/code&gt; node just beside every template's controls elements&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;model alteration&lt;/strong&gt;: &lt;em&gt;formControls&lt;/em&gt; have to be enabled/disabled by user interaction with our checkboxes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While the latter is quite straightforward, because it's basically how every JS/TS framework's form interaction package is supposed to be used, the first one could present more than one issue to be implemented, even if in our purposely limited specific test case all the tricky aspects will be kept aside.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show the code
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Decorator definition and constructor injection:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Directive&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[selectablePlain]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SelectablePlainDirective&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Renderer2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;hostEl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ElementRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NgControl&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We set our selector to be used in template as &lt;code&gt;selectablePlain&lt;/code&gt;, and in particular I declared this directive as &lt;code&gt;standalone&lt;/code&gt;, new trend in Angular world (nothing would have changed declaring it in &lt;em&gt;@NgModule&lt;/em&gt; like it was mandatory until Angular v14).&lt;br&gt;
Then we inject some dependencies capable of executing our logic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://angular.io/api/core/Renderer2" rel="noopener noreferrer"&gt;&lt;strong&gt;Renderer2&lt;/strong&gt;&lt;/a&gt;: an Angular abstraction on top of WebAPI's &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Document" rel="noopener noreferrer"&gt;Document&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Node" rel="noopener noreferrer"&gt;Node&lt;/a&gt; interfaces, providing some safe methods to programmatically manipulate DOM elements at low level.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://angular.io/api/core/ElementRef" rel="noopener noreferrer"&gt;&lt;strong&gt;ElementRef&lt;/strong&gt;&lt;/a&gt;: injecting this class in a directive, we get access to an hosting element reference. In practice, we'll get in code an object wrapping DOM element to which directive is applied (&lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;s or &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt;s in our case)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://angular.io/api/forms/NgControl" rel="noopener noreferrer"&gt;&lt;strong&gt;NgControl&lt;/strong&gt;&lt;/a&gt;: this class is common ancestor to &lt;code&gt;NgModel&lt;/code&gt;, &lt;code&gt;FormControlDirective&lt;/code&gt; and &lt;code&gt;FormControlName&lt;/code&gt;, meaning that injecting it in place of any specific subclasses makes our directive more versatile and not dependent on the specific &lt;code&gt;Form&lt;/code&gt; implementation the user chose for his template (having we bound every control with a &lt;code&gt;formControlName&lt;/code&gt; directive, we would have obtained the same result injecting &lt;code&gt;FormControlName&lt;/code&gt; class).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Constructor body
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checkBox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checkBox&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checkbox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Inside constructor body we use our &lt;em&gt;Renderer2&lt;/em&gt; instance to create the element to be added: we can see its &lt;em&gt;createElement&lt;/em&gt; method accepting just the name of the tag to be generated.&lt;br&gt;
After that, we leverage its &lt;em&gt;setAttribute&lt;/em&gt; method to assign the &lt;code&gt;type="checkbox"&lt;/code&gt; to this &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; element just created as per our needs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertBefore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parentNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hostEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeElement&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checkBox&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nextSibling&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hostEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What looks like such a convoluted call, it's just a fill-in for a missing &lt;em&gt;insertAfter&lt;/em&gt; method.&lt;br&gt;
Leveraging our injected &lt;em&gt;ElementRef&lt;/em&gt;, we retrieve our hosting element stored into its &lt;code&gt;nativeElement&lt;/code&gt; property, and pass it to a couple of calls used as arguments of &lt;em&gt;insertBefore&lt;/em&gt;.&lt;br&gt;
This method is supposed to insert a new node as &lt;strong&gt;previous sibling&lt;/strong&gt; of a target one, and expects three arguments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;parent of the target node&lt;/li&gt;
&lt;li&gt;new node to be inserted&lt;/li&gt;
&lt;li&gt;target node before which inserting new one&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trick is in the last one: we pass as target node &lt;strong&gt;the next sibling&lt;/strong&gt; of our hosting element, leading renderer to actually put the new element between our hosting one and its next sibling (if any).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checkBox&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;enable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;disable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the end, we attach a listener to our checkbox' &lt;code&gt;change&lt;/code&gt; event, responsible of doing what is our real objective: if control is already disabled, a click on the checkbox should call enabling method, otherwise disable that.&lt;/p&gt;

&lt;h3&gt;
  
  
  ngOnInit for late setup
&lt;/h3&gt;

&lt;p&gt;As &lt;a href="https://github.com/angular/angular/issues/35330" rel="noopener noreferrer"&gt;this open ticket&lt;/a&gt; demonstrates, &lt;code&gt;NgControl.control&lt;/code&gt; gets populated only after &lt;em&gt;OnChange&lt;/em&gt; lifecycle, so every &lt;em&gt;NgControl&lt;/em&gt; property related to runtime control values is undefined in constructor.&lt;br&gt;
That's why we need to put part of our logic inside &lt;em&gt;ngOnInit&lt;/em&gt; lifecycle callback.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checkBox&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we're setting the initial checkbox state: we don't wanna see a checkbox associated to a control initially disabled appearing as checked, nor vice-versa.&lt;br&gt;
So we check the initial status of our control, and set our checkbox' &lt;code&gt;checked&lt;/code&gt; property accordingly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusChanges&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DISABLED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checkBox&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checkBox&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Last thing missing is the guarantee that every programmatically change in control status will be reflected in related checkbox status: if some piece of TS code at some point disables our control, it would be misleading seeing its bound checkbox showing a flag as if it was still enabled.&lt;br&gt;
To avoid this, we subscribe to &lt;code&gt;NgControl.statusChanges&lt;/code&gt; observable, unchecking our checkbox everytime it emits a &lt;code&gt;"DISABLED"&lt;/code&gt; value, and doing the opposite for everything else it should produce (&lt;code&gt;"PENDING" | "VALID" | "INVALID"&lt;/code&gt;).&lt;br&gt;
Why we cannot rely on this for initial value too?&lt;br&gt;
Because being it a &lt;em&gt;status*Changes*&lt;/em&gt; emitter, it will not emit control's initial value.&lt;br&gt;
But we are working in Angular after all, so we surely are confident with RxJs operators and know that &lt;a href="https://rxjs.dev/api/operators/startWith" rel="noopener noreferrer"&gt;startWith&lt;/a&gt; can do the trick here, so we fuse the last two snippets in a single one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusChanges&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;startWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DISABLED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checkBox&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checkBox&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can verify our controls are correctly disabled:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1wn7pa09sfjch712i238.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1wn7pa09sfjch712i238.png" alt="Submit without disabled controls" width="600" height="420"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;Final result is satisfying, but we need to keep in mind our testcase was tailored for the sake of the example.&lt;br&gt;
If model interaction can be bent to work as expected most of the times, the same can't be said for DOM manipulation, where an initial template just a bit less smooth than the unrealistic one we used in this post can lead to totally different outputs.&lt;br&gt;
Real cases turn the creation of a general-purpose directive into an extremely time-wasting exercise, with little to no advantage compared to manually adding needed checkboxes anywhere we need them, maybe enriching them with a pure model-oriented custom directive, specific for the case.&lt;br&gt;
We'll get a taste of the issue in the next article, where we will try to replicate this task with an Angular Material styled form.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>AnimationRenderer: listening and playing</title>
      <dc:creator>Gianpiero Errigo</dc:creator>
      <pubDate>Mon, 02 Jan 2023 10:59:34 +0000</pubDate>
      <link>https://dev.to/playfulprogramming-angular/animationrenderer-listening-and-playing-4i3a</link>
      <guid>https://dev.to/playfulprogramming-angular/animationrenderer-listening-and-playing-4i3a</guid>
      <description>&lt;p&gt;In the first two articles of this series we learned how &lt;em&gt;AnimationRendererFactory&lt;/em&gt; generates its renderers.&lt;br&gt;
Now we're gonna look at what "animating rendering transition" means concretely.&lt;/p&gt;


&lt;h2&gt;
  
  
  Animations: Transition vs Timeline
&lt;/h2&gt;

&lt;p&gt;This series focuses on &lt;em&gt;transition animations&lt;/em&gt;, declarative ones executed during state changes of an element.&lt;br&gt;
There's another type of animation available in Angular: &lt;em&gt;timeline animation&lt;/em&gt; ones, that can be explicitly issued after having built a dedicated player following the flow started by &lt;a href="https://angular.io/api/animations/AnimationBuilder" rel="noopener noreferrer"&gt;&lt;strong&gt;AnimationBuilder&lt;/strong&gt;&lt;/a&gt; class.&lt;br&gt;
These two flavours share big part of animation lifecycle but differ in some details, thus they need to notify their nature to common gears.&lt;br&gt;
In the end they both rely on elements' properties for their job: transitions expecting to find them declared in templates, while programmatic ones translating command issued by the player in DOM nodes' properties.&lt;br&gt;
To distinguish between the two, the framework defines a simple "contract":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;transition animations properties&lt;/strong&gt; will be prepended by a single &lt;strong&gt;&lt;code&gt;@&lt;/code&gt;&lt;/strong&gt; character (explictly added by the coder during template writing, &lt;code&gt;[@yourAnimationName]="yourCompProp"&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;timeline animations properties&lt;/strong&gt; will automatically come prepended by two &lt;strong&gt;&lt;code&gt;@@&lt;/code&gt;&lt;/strong&gt; characters by &lt;a href="https://github.com/angular/angular/blob/470738c8f775145630a07be783e50dac5d2194e5/packages/platform-browser/animations/src/animation_builder.ts#L46" rel="noopener noreferrer"&gt;&lt;strong&gt;RendererAnimationPlayer&lt;/strong&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;issueAnimationCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AnimationRenderer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`@@&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Even in this article we will not study timeline animations, but this preamble was due because at some point the classes we're going to examine will execute the checks to route flow in the right path.&lt;/p&gt;

&lt;h2&gt;
  
  
  AnimationRenderer overrides: entry points to animation flow
&lt;/h2&gt;

&lt;p&gt;Our &lt;em&gt;AnimationRendererFactory&lt;/em&gt; detected some triggers declared inside &lt;code&gt;@Component&lt;/code&gt; metadata and generated an instance of &lt;a href="https://github.com/angular/angular/blob/27da7338ea8f3bf5336d77ed1877cfa6a1974d52/packages/platform-browser/animations/src/animation_renderer.ts#L243" rel="noopener noreferrer"&gt;&lt;strong&gt;AnimationRenderer&lt;/strong&gt;&lt;/a&gt;.&lt;br&gt;
Looking at the code, we notice that it extends the "dumb" &lt;em&gt;BaseAnimationRenderer&lt;/em&gt; class covered in this series' first article.&lt;br&gt;
It adds two important overrides: &lt;strong&gt;setProperty&lt;/strong&gt; and &lt;strong&gt;listen&lt;/strong&gt;.&lt;br&gt;
First one is &lt;strong&gt;Renderer2&lt;/strong&gt;'s method to add/change DOM nodes' properties, that as we already explained, is the way the framework uses to trigger animation flow.&lt;br&gt;
The latter instead, set an event listener on DOM nodes, and will be used by the framework to issue eventual callbacks we defined (for &lt;em&gt;transition animations&lt;/em&gt;, think about &lt;strong&gt;start&lt;/strong&gt; and &lt;strong&gt;done&lt;/strong&gt; phases' output).&lt;/p&gt;

&lt;p&gt;Let's see its constructor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AnimationRenderer&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BaseAnimationRenderer&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Renderer2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AnimationRendererFactory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;namespaceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delegate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Renderer2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AnimationEngine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onDestroy&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;namespaceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delegate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onDestroy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;namespaceId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;namespaceId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;a reference to its factory, but this is only used for some kind of optimization we will not investigate in this article (&lt;a href="https://github.com/angular/angular/commit/6cb93c1fac669de591dfa0cb8380381ee1a23506" rel="noopener noreferrer"&gt;here&lt;/a&gt; you can find relative commit, if you're curious).&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;namespaceId&lt;/code&gt; uniquely identifying this renderer and extensively explained in previous article&lt;/li&gt;
&lt;li&gt;a delegate &lt;em&gt;*DOMRenderer&lt;/em&gt; for non-animated tasks&lt;/li&gt;
&lt;li&gt;an &lt;em&gt;AnimationEngine&lt;/em&gt; in charge of checking the nature of the animation and routing it to dedicated engine (&lt;em&gt;TransitionAnimationEngine&lt;/em&gt; or &lt;em&gt;TimelineAnimationEngine&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;a destruction callback&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's all it needs to do its job.&lt;/p&gt;

&lt;h2&gt;
  
  
  setProperty(...): fire up this thing!
&lt;/h2&gt;

&lt;h4&gt;
  
  
  AnimationRenderer
&lt;/h4&gt;

&lt;p&gt;We already told every animation starts with a change in the value of some dedicated DOM nodes properties, applied by &lt;em&gt;AnimationRenderer&lt;/em&gt;'s &lt;strong&gt;setProperty&lt;/strong&gt; override:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;override&lt;/span&gt; &lt;span class="nf"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;ANIMATION_PREFIX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;DISABLE_ANIMATIONS_FLAG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disableAnimations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;namespaceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;delegate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It accepts the expected arguments: the element to which applying the property, the name of the property and its value.&lt;br&gt;
Let's examine its logic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;first it checks if property is actually an animation binding, verifying its name starts with an &lt;em&gt;ANIMATION_PREFIX&lt;/em&gt;, namely a &lt;code&gt;@&lt;/code&gt; character.
Otherwise, the call is passed to delegated native &lt;em&gt;*DOMRenderer&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;if the binding turns out as an animation one, code will look for a disabling instruction, that could have been issued assigning to the node a property named &lt;code&gt;@.disabled&lt;/code&gt;. So for optimization it first checks for a dot character &lt;code&gt;.&lt;/code&gt; following &lt;code&gt;@&lt;/code&gt;, and after that for the string &lt;code&gt;disabled&lt;/code&gt;. If found, it will ask the engine to disable any animation for that element and its children&lt;/li&gt;
&lt;li&gt;when the binding is an actual animation request instead, &lt;a href="https://github.com/angular/angular/blob/f58ad86e51817f83ff18db790a347528262b850b/packages/animations/browser/src/render/animation_engine_next.ts#L71" rel="noopener noreferrer"&gt;&lt;strong&gt;AnimationEngine&lt;/strong&gt;&lt;/a&gt;' &lt;em&gt;process&lt;/em&gt; method is called, passing as arguments:

&lt;ul&gt;
&lt;li&gt;specific &lt;em&gt;namespaceId&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;the element&lt;/li&gt;
&lt;li&gt;name of the property &lt;strong&gt;stripped of its first &lt;code&gt;@&lt;/code&gt; character&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;new value to be assigned to the property&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  AnimationEngine
&lt;/h4&gt;

&lt;p&gt;Here's how &lt;strong&gt;AnimationEngine&lt;/strong&gt; processes the call.&lt;br&gt;
Remember that &lt;em&gt;AnimationRenderer&lt;/em&gt; already stripped first &lt;code&gt;@&lt;/code&gt; char.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;namespaceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseTimelineCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_timelineEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_transitionEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;namespaceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;it immediately checks first character of the property name:

&lt;ul&gt;
&lt;li&gt;if it's again a &lt;code&gt;@&lt;/code&gt; character, we are facing a &lt;em&gt;timeline animations&lt;/em&gt; request, that as we already seen gets constructed with the structure &lt;code&gt;@@${id}:${command}&lt;/code&gt;. Calling &lt;em&gt;parseTimelineCommand&lt;/em&gt;, property name gets tokenized stripping remaining leading &lt;code&gt;@&lt;/code&gt; and using colon char &lt;code&gt;:&lt;/code&gt; as separator, extracting &lt;em&gt;id&lt;/em&gt; of the specific &lt;a href="https://github.com/angular/angular/blob/470738c8f775145630a07be783e50dac5d2194e5/packages/platform-browser/animations/src/animation_builder.ts#L36" rel="noopener noreferrer"&gt;&lt;strong&gt;BrowserAnimationFactory&lt;/strong&gt;&lt;/a&gt; and the name of the command to be executed. Value of the property (if any) gets passed as array of arguments to the command&lt;/li&gt;
&lt;li&gt;if received property's first character is anything but &lt;code&gt;@&lt;/code&gt;, we're surely dealing with a &lt;em&gt;transition animation&lt;/em&gt;, thus the code passes the request to &lt;a href="https://github.com/angular/angular/blob/f58ad86e51817f83ff18db790a347528262b850b/packages/animations/browser/src/render/transition_animation_engine.ts#L527" rel="noopener noreferrer"&gt;&lt;strong&gt;TransitionAnimationEngine&lt;/strong&gt;&lt;/a&gt;'s &lt;em&gt;trigger&lt;/em&gt; method, responsible of bootstrapping the logic of &lt;a href="https://github.com/angular/angular/blob/f58ad86e51817f83ff18db790a347528262b850b/packages/animations/browser/src/render/transition_animation_engine.ts#L112" rel="noopener noreferrer"&gt;&lt;strong&gt;TransitionAnimationNamespace&lt;/strong&gt;&lt;/a&gt; related method.
This one, after a really complex logic aiming at collecting and enqueueing all possible involved animations on the elements of its pertinence, will call one or more &lt;em&gt;TransitionAnimationPlayer&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  listen(...): catch that animation event!
&lt;/h2&gt;

&lt;h4&gt;
  
  
  AnimationRenderer
&lt;/h4&gt;

&lt;p&gt;Whatever the nature of our animation, we could have setup some operations to be executed just before or after the animation has been played (and in case of &lt;em&gt;timeline animations&lt;/em&gt;, before or after player gets explicitly destroyed too). &lt;br&gt;
To achieve this goal we assign callbacks to some listeners exposed by the framework.&lt;br&gt;
For &lt;em&gt;transition animations&lt;/em&gt; we can bind desired functions to some &lt;em&gt;phase&lt;/em&gt; outputs in template, in the form &lt;code&gt;(@yourAnimationName.start)="yourFunction()"&lt;/code&gt; or &lt;code&gt;(@yourAnimationName.done)="yourFunction()"&lt;/code&gt;.&lt;br&gt;
A rule similar to the one we observed for &lt;code&gt;setProperties&lt;/code&gt; has to be obliged:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;transition animations events&lt;/strong&gt; have to be prepended by a single &lt;strong&gt;&lt;code&gt;@&lt;/code&gt;&lt;/strong&gt; character&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;timeline animations events&lt;/strong&gt; will automatically come prepended by two &lt;strong&gt;&lt;code&gt;@@&lt;/code&gt;&lt;/strong&gt; characters by &lt;a href="https://github.com/angular/angular/blob/470738c8f775145630a07be783e50dac5d2194e5/packages/platform-browser/animations/src/animation_builder.ts#L56" rel="noopener noreferrer"&gt;&lt;strong&gt;RendererAnimationPlayer&lt;/strong&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;_listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`@@&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;These events will be caught by &lt;strong&gt;AnimationRenderer&lt;/strong&gt;'s &lt;em&gt;listen&lt;/em&gt; method, that we're going to analyze:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;override&lt;/span&gt; &lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;window&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;document&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;ANIMATION_PREFIX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;resolveElementFromTarget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;phase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// @listener.phase is for trigger animation callbacks&lt;/span&gt;
    &lt;span class="c1"&gt;// @@listener is for animation builder callbacks&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nx"&gt;ANIMATION_PREFIX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;phase&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseTriggerCallbackName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;namespaceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;phase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;countId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scheduleListenerCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;countId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;delegate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It accepts three arguments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;target on which listen for the event&lt;/li&gt;
&lt;li&gt;name of the event&lt;/li&gt;
&lt;li&gt;function to be executed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, its logic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;first check is something we already saw on &lt;code&gt;setProperty&lt;/code&gt; implementation: look at first character of the event name, if it doesn't start with a &lt;code&gt;@&lt;/code&gt; character, it's not an animation event, so its management can be passed to delegated native &lt;em&gt;*DOMRenderer&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;target gets processed in case it comes as a string, and its respective HTML element gets returned (at least for &lt;em&gt;transition animations&lt;/em&gt; I can't see when this can happen, considering listener is added by Angular template parser, and that &lt;em&gt;window&lt;/em&gt;, &lt;em&gt;document&lt;/em&gt; and &lt;em&gt;body&lt;/em&gt; elements are outside its control. Whoever should know better is welcome in comments)&lt;/li&gt;
&lt;li&gt;first &lt;code&gt;@&lt;/code&gt; character gets stripped from event name&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;first character of current name event (just stripped of the mandatory &lt;code&gt;@&lt;/code&gt; one) gets checked again, because:    &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if it's &lt;strong&gt;not&lt;/strong&gt; another &lt;code&gt;@&lt;/code&gt; char, it means we got a &lt;em&gt;transition animation&lt;/em&gt; event, so we need to tokenize it:

&lt;ul&gt;
&lt;li&gt;on the left of dot character &lt;code&gt;.&lt;/code&gt; we got our &lt;em&gt;trigger&lt;/em&gt; name&lt;/li&gt;
&lt;li&gt;on right side there's the name of its phase for which we want to register a listener&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;if instead a second &lt;code&gt;@&lt;/code&gt; char is found, the name gets passed down the chain as-is, ditching manipulation task to &lt;strong&gt;AnimationEngine&lt;/strong&gt; as we'll see later&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;now we're good to call &lt;strong&gt;AnimationEngine&lt;/strong&gt;'s &lt;em&gt;listen&lt;/em&gt; method passing as its arguments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;namespaceId proper of this renderer&lt;/li&gt;
&lt;li&gt;element resolved as explained&lt;/li&gt;
&lt;li&gt;name of the event (extracted from original one for &lt;em&gt;transition animations&lt;/em&gt;, or completely cloned for &lt;em&gt;timeline animations&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;name of the phase (again extracted, or just an empty string for &lt;em&gt;timeline&lt;/em&gt; ones)&lt;/li&gt;
&lt;li&gt;a wrapper function around our real callback scheduling it on &lt;em&gt;microtask&lt;/em&gt;, but for the sake of simplicity in this article we will consider as if it received just our callback directly&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  AnimationEngine
&lt;/h4&gt;

&lt;p&gt;As for &lt;em&gt;setProperty&lt;/em&gt; call chain,the role of &lt;strong&gt;AnimationEngine&lt;/strong&gt; in even listening is just a little more than the one of a "router" to the correct specific engine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;namespaceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;eventPhase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// @@listen&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseTimelineCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_timelineEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_transitionEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;namespaceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;eventPhase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's a check on event name's first character that we should used to, now: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if that's &lt;code&gt;@&lt;/code&gt;, it means it has not been tokenized by caller &lt;strong&gt;AnimationRenderer&lt;/strong&gt;'s &lt;em&gt;listen&lt;/em&gt; method and that we're processing a &lt;em&gt;timeline animation event&lt;/em&gt;, so

&lt;ul&gt;
&lt;li&gt;proceed to strip leading &lt;code&gt;@&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;split remaining string using colon &lt;code&gt;:&lt;/code&gt; as separator to get &lt;em&gt;id&lt;/em&gt; of the player and name of &lt;em&gt;action&lt;/em&gt; to perform&lt;/li&gt;
&lt;li&gt;call dedicated &lt;a href="https://github.com/angular/angular/blob/f58ad86e51817f83ff18db790a347528262b850b/packages/animations/browser/src/render/timeline_animation_engine.ts#L25" rel="noopener noreferrer"&gt;&lt;strong&gt;TimelineAnimationEngine&lt;/strong&gt;&lt;/a&gt;'s &lt;em&gt;listen&lt;/em&gt; method, that will take care of selecting right event's callback registered for specified player&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;otherwise we can pass it as-is as argument of &lt;a href="https://github.com/angular/angular/blob/f58ad86e51817f83ff18db790a347528262b850b/packages/animations/browser/src/render/transition_animation_engine.ts#L527" rel="noopener noreferrer"&gt;&lt;strong&gt;TransitionAnimationEngine&lt;/strong&gt;&lt;/a&gt; version of &lt;em&gt;listen&lt;/em&gt; method, that after fetching the right &lt;strong&gt;AnimationTransitionNamespace&lt;/strong&gt; instance by the &lt;em&gt;namespaceId&lt;/em&gt; it received, will call its &lt;em&gt;listen&lt;/em&gt; method, the one actually responsible of adding the listener to the array bound to that element.&lt;/li&gt;

&lt;/ul&gt;




&lt;p&gt;I hope at this point the reader has at least a shallow understanding of transition animation registering flow in Angular.&lt;br&gt;
I purposely left out some implementation details, and stopped digging down call chain before entering the real execution logic of players and callbacks, because that would have been confusing for you at least as much as it is for me.&lt;br&gt;
My intent was to write just about concepts I correctly grasped but, as usual, I'm open to any review suggested in comments.&lt;/p&gt;

&lt;p&gt;Thanks for reading! &lt;/p&gt;

</description>
      <category>angular</category>
      <category>webdev</category>
      <category>typescript</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Angular registering animation triggers</title>
      <dc:creator>Gianpiero Errigo</dc:creator>
      <pubDate>Tue, 27 Dec 2022 11:11:48 +0000</pubDate>
      <link>https://dev.to/playfulprogramming-angular/angular-registering-animation-triggers-5gpg</link>
      <guid>https://dev.to/playfulprogramming-angular/angular-registering-animation-triggers-5gpg</guid>
      <description>&lt;p&gt;This post keeps digging into &lt;strong&gt;AnimationRendererFactory&lt;/strong&gt; creation routine, with a  focus on triggers registering logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  AnimationRenderer, the real one
&lt;/h2&gt;

&lt;p&gt;Inside first article of this series we examined main concepts about Angular's &lt;strong&gt;AnimationRendererFactory&lt;/strong&gt; and how it creates a "dumb" &lt;strong&gt;BaseAnimationRenderer&lt;/strong&gt; to allow components not declaring any &lt;a href="https://angular.io/api/animations/trigger" rel="noopener noreferrer"&gt;&lt;strong&gt;animation trigger&lt;/strong&gt;&lt;/a&gt; to be known by the animation engine.&lt;/p&gt;

&lt;p&gt;In this post we're going to analyze the creation process of a more interesting child class of the former renderer: &lt;strong&gt;AnimationRenderer&lt;/strong&gt;.&lt;br&gt;
An instance of this type is the one generated for components declaring one or more triggers inside their &lt;code&gt;@Component&lt;/code&gt; decorator metadata &lt;code&gt;animations&lt;/code&gt; property, which are needed to be registered with the engine before injecting the latter inside renderer constructor.&lt;/p&gt;
&lt;h2&gt;
  
  
  RendererType2: component's rendering metadata
&lt;/h2&gt;

&lt;p&gt;We already seen factory's &lt;a href="https://github.com/angular/angular/blob/main/packages/platform-browser/animations/src/animation_renderer.ts#L44" rel="noopener noreferrer"&gt;&lt;strong&gt;createRenderer&lt;/strong&gt;&lt;/a&gt; expecting a &lt;em&gt;type&lt;/em&gt; argument, declared as &lt;a href="https://angular.io/api/core/RendererType2" rel="noopener noreferrer"&gt;&lt;strong&gt;RendererType2&lt;/strong&gt;&lt;/a&gt;.&lt;br&gt;
This interface is defined to store some rendering information generated at component creation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;RendererType2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;encapsulation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ViewEncapsulation&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[])[];&lt;/span&gt;
  &lt;span class="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If second and third ones remind you of some &lt;code&gt;@Component&lt;/code&gt; decorator's metadata, that's because the framework takes their values exactly from there when creating a component, being it routed or a child one.&lt;br&gt;
Let's examine them one by one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;id&lt;/strong&gt;: this is an identifier generated by compiler for the specific Component &lt;strong&gt;class&lt;/strong&gt;.
Don't be fooled by misleading official doc definition:
&lt;code&gt;A unique identifying string for the new renderer&lt;/code&gt;.
The assertion could let the reader think everytime he creates a new instance of the component, this will get a new &lt;strong&gt;id&lt;/strong&gt;, but that's not true.
The property has to be considered as a &lt;em&gt;static class field&lt;/em&gt;: &lt;strong&gt;every instance of the same @Component class will get the same id&lt;/strong&gt;.
Official definition is not wrong per-se, but take in account only &lt;em&gt;DomRendererFactory2&lt;/em&gt;, that for every instance of the same component will return the same cached renderer (at least for &lt;em&gt;ViewEncapsulation.Emulated&lt;/em&gt;), making the id effectively unique for all &lt;em&gt;EmulatedEncapsulationDomRenderer2&lt;/em&gt; generated for that class, and obviously for the single instance of &lt;em&gt;DefaultDomRenderer2&lt;/em&gt; returned in some conditions.
This definition loses its accountability when talking about &lt;em&gt;AnimationRenderer&lt;/em&gt;, where two different instances of the same component will get assigned two different instances of the renderer, due to the introduction of &lt;em&gt;namespace&lt;/em&gt; concept. (More about this later)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;encapsulation&lt;/strong&gt;: with this value &lt;em&gt;DomRendererFactory2&lt;/em&gt; choose which type of encapsulation-specific renderer to create, through a simple switch statement:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;encapsulation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;ViewEncapsulation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Emulated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="nx"&gt;renderer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EmulatedEncapsulationDomRenderer2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eventManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sharedStylesHost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;ViewEncapsulation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ShadowDom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ShadowDomRenderer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eventManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sharedStylesHost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defaultRenderer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;styles&lt;/strong&gt;: CSS style or list of styles to be assigned to host element of rendered component&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;data&lt;/strong&gt;: this property shaped as an open dictionary could sound "alien", but it's actually the one used to define a whole set of optional characteristics of the component that's gonna be created.
It's crucial for our case study because that's where &lt;em&gt;AnimationRenderer&lt;/em&gt; will look for declared &lt;a href="https://angular.io/api/animations/AnimationTriggerMetadata" rel="noopener noreferrer"&gt;&lt;strong&gt;AnimationTriggerMetadata&lt;/strong&gt;&lt;/a&gt; to be registered.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Namespace independently tracking state of component instances triggers
&lt;/h2&gt;

&lt;p&gt;To keep track of individual component instances' triggers state, Angular animation package introduces the concept of &lt;a href="https://github.com/angular/angular/blob/f58ad86e51817f83ff18db790a347528262b850b/packages/animations/browser/src/render/transition_animation_engine.ts#L112" rel="noopener noreferrer"&gt;&lt;strong&gt;AnimationTransitionNamespace&lt;/strong&gt;&lt;/a&gt;.&lt;br&gt;
You can think of it as a wrapper grouping all elements of a single animated component instance.&lt;br&gt;
As already explained, &lt;em&gt;id&lt;/em&gt; property from &lt;em&gt;Renderer2&lt;/em&gt; interface is unique for component's &lt;strong&gt;class&lt;/strong&gt;, thus is not enough to distinguish among different instances of same component.&lt;br&gt;
That's why the factory declares a new property, incremented on every &lt;em&gt;AnimationRenderer&lt;/em&gt; creation, and concatenated with &lt;em&gt;Renderer2&lt;/em&gt;'s &lt;em&gt;id&lt;/em&gt; to compose an identifier unique for &lt;em&gt;namespace&lt;/em&gt;, used to register the latter with the engine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;componentId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;namespaceId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_currentId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_currentId&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;namespaceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hostElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can notice these identifiers added as a class to every DOM element of the host component: they are all prepended by &lt;code&gt;ng-tns-&lt;/code&gt; string:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fec95pc1rbabda51273dk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fec95pc1rbabda51273dk.png" alt="ns_classes_added" width="800" height="79"&gt;&lt;/a&gt;&lt;br&gt;
Look at the &lt;code&gt;ng-tns-c19-8&lt;/code&gt; class assigned to &lt;code&gt;&amp;lt;app-home&amp;gt;&lt;/code&gt; element: this means that &lt;code&gt;HomeComponent&lt;/code&gt; got &lt;code&gt;c19&lt;/code&gt; as its &lt;code&gt;RendererType2.id&lt;/code&gt;, and that this specific instance has been bound to the &lt;strong&gt;ninth&lt;/strong&gt; (_&lt;em&gt;currentId&lt;/em&gt; is initialized as &lt;em&gt;0&lt;/em&gt;) &lt;em&gt;AnimationRenderer&lt;/em&gt; created by the factory, which being injected as singleton make that number the creation order along the whole app.&lt;br&gt;
(AFAIK, these identifiers have just a naming purpose, so their order should be of no interest.)&lt;/p&gt;

&lt;p&gt;You can see that the same class has been added to everyone of its children, both &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;app-child&amp;gt;&lt;/code&gt; nodes.&lt;br&gt;
But in the second a difference catches the eye:&lt;br&gt;
another &lt;em&gt;namespace class&lt;/em&gt; is assigned beside the parent's one, &lt;code&gt;ng-tns-c18-9&lt;/code&gt;.&lt;br&gt;
It's clear that this namespace refers to a different component class than the parent one (&lt;code&gt;c-18&lt;/code&gt; vs &lt;code&gt;c-19&lt;/code&gt;). &lt;br&gt;
That's expected, being &lt;code&gt;&amp;lt;app-child&amp;gt;&lt;/code&gt; the host element of a different component. &lt;br&gt;
Since &lt;code&gt;ChildComponent&lt;/code&gt;'s declares some triggers inside  its decorator &lt;code&gt;animations&lt;/code&gt; property, a new &lt;em&gt;AnimationRenderer&lt;/em&gt; has been created for it, thus a new namespace.&lt;br&gt;
So, being this component instance both declaring some animations, both included in the template of an animated parent component, it's part of two different namespaces.&lt;/p&gt;

&lt;p&gt;Looking at third childnode, another &lt;code&gt;&amp;lt;app-child&amp;gt;&lt;/code&gt; element, we notice that parent namespace class is still there, but its own namespace class is different than the one of its sibling: &lt;code&gt;ng-tns-c18-10&lt;/code&gt;, same component type id but counter incremented by one.&lt;br&gt;
This concurs with source code we analyzed earlier: even being instances of the same component class, they got separate renderers and are part of distinct namespaces.&lt;/p&gt;

&lt;p&gt;Last thing worth noting is the inner elements of child host elements, in our example a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; inside the expanded last &lt;code&gt;&amp;lt;app-child&amp;gt;&lt;/code&gt;: it gets the namespace of component it belongs to, &lt;code&gt;ng-tns-c18-10&lt;/code&gt;, but not the one of its grandparent, like its host element does.&lt;br&gt;
This sounds quite logical, considering that &lt;code&gt;&amp;lt;app-child&amp;gt;&lt;/code&gt; is included into &lt;code&gt;HomeComponent&lt;/code&gt;'s template, while child nodes inside its own template are not.&lt;/p&gt;
&lt;h2&gt;
  
  
  Actual registration of triggers
&lt;/h2&gt;

&lt;p&gt;On top of the source file declaring this factory, we got a couple of type declarations (a type and an interface, to be precise)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Define a recursive type to allow for nested arrays of `AnimationTriggerMetadata`. Note that an&lt;/span&gt;
&lt;span class="c1"&gt;// interface declaration is used as TypeScript prior to 3.7 does not support recursive type&lt;/span&gt;
&lt;span class="c1"&gt;// references, see https://github.com/microsoft/TypeScript/pull/33050 for details.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;NestedAnimationTriggerMetadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;AnimationTriggerMetadata&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nx"&gt;RecursiveAnimationTriggerMetadata&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;RecursiveAnimationTriggerMetadata&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;NestedAnimationTriggerMetadata&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They look quite tricky at first sight, but reading accompanying comment and analyzing their definitions, it turns out they just form a recursive data structure.&lt;br&gt;
Their use, as we're gonna see, addresses a problem arisen switching from &lt;em&gt;ViewEngine&lt;/em&gt; to &lt;em&gt;Ivy&lt;/em&gt;, with the new one losing the capabilities of flattening metadata arrays, resulting in wrong registering of triggers passed to &lt;code&gt;@Component&lt;/code&gt; as nested arrays, leading to runtime errors.&lt;/p&gt;

&lt;p&gt;Compiler parsed our &lt;code&gt;@Component&lt;/code&gt; decorators metadata and stored their &lt;code&gt;animations&lt;/code&gt; field content inside &lt;code&gt;animation&lt;/code&gt; property of aforementioned &lt;code&gt;data&lt;/code&gt; open-dictionary field of related &lt;em&gt;RendererType2&lt;/em&gt; object. &lt;br&gt;
Renderer creation routine casts this value to an array of the recursive data structure we already seen has been defined on purpose.&lt;br&gt;
Then it iterates over that, issuing a registration function for every trigger it finds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;animationTriggers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;animation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;NestedAnimationTriggerMetadata&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="nx"&gt;animationTriggers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;registerTrigger&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This registering function has to take in account the recursive nature of this data structure: the object it gets passed as argument could be an actual &lt;a href="https://angular.io/api/animations/AnimationTriggerMetadata" rel="noopener noreferrer"&gt;&lt;strong&gt;trigger&lt;/strong&gt;&lt;/a&gt; to be registered, or an array itself containing triggers definitions, and even an array containing other arrays. This nesting has an unpredictable depth, so our function has to be implemented with a recursive logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;registerTrigger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NestedAnimationTriggerMetadata&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;registerTrigger&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerTrigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;componentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;namespaceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hostElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see it's a common flattening algorithm often used with recursively nested arrays: a function recalling itself until its argument is proved to be an array, when this check fails we are in presence of a trigger definition to be registered with engine (and in turn with specific namespace).&lt;/p&gt;

&lt;p&gt;When all defined triggers have been registered, a new &lt;strong&gt;AnimationRenderer&lt;/strong&gt; can be built and returned, injected with the &lt;code&gt;namespaceId&lt;/code&gt; composed in previous phase.&lt;/p&gt;




&lt;p&gt;Hope this post has been an interesting reading, and since the topic has still many "obscure" details for me, I encourage anyone with a constructive suggestion to get in touch in comments.&lt;br&gt;
Next time we'll take a look at &lt;em&gt;AnimationRenderer&lt;/em&gt; actual work.&lt;br&gt;
Cheers.&lt;/p&gt;

</description>
      <category>angular</category>
    </item>
    <item>
      <title>AnimationFactory: how Angular creates animation renderers</title>
      <dc:creator>Gianpiero Errigo</dc:creator>
      <pubDate>Tue, 20 Dec 2022 11:08:14 +0000</pubDate>
      <link>https://dev.to/playfulprogramming-angular/animationfactory-how-angular-creates-animation-renderers-1m6b</link>
      <guid>https://dev.to/playfulprogramming-angular/animationfactory-how-angular-creates-animation-renderers-1m6b</guid>
      <description>&lt;p&gt;This article is intended to be the beginning of a short series about Angular transition animations mechanism source code, a niche in Angular codebase often considered confusing and not enough documented.&lt;/p&gt;




&lt;h2&gt;
  
  
  Angular transition animations
&lt;/h2&gt;

&lt;p&gt;For &lt;em&gt;"Transition Animations"&lt;/em&gt; in Angular we mean adding transitioning effects between elements' state changes.&lt;br&gt;
Normally this is done by binding a &lt;em&gt;trigger&lt;/em&gt; to a property that will get the values of the &lt;em&gt;states&lt;/em&gt; whose transition we want to animate.&lt;br&gt;
They share only last part of their flow with &lt;em&gt;"Timeline Animations&lt;/em&gt;", the ones executed by explicitly operating &lt;em&gt;Animation Players&lt;/em&gt;, and that will not be a topic of these articles.&lt;/p&gt;
&lt;h2&gt;
  
  
  Quick recap on Angular Renderers
&lt;/h2&gt;

&lt;p&gt;To manipulate the DOM without directly accessing its nodes Angular leverages &lt;em&gt;Renderers&lt;/em&gt;, tools designed to be a level of abstraction on native DOM operations.&lt;br&gt;
They're shaped upon abstract class &lt;a href="https://angular.io/api/core/Renderer2" rel="noopener noreferrer"&gt;&lt;strong&gt;Renderer2&lt;/strong&gt;&lt;/a&gt;, and are fundamental in transition animations context because some of their flavors get used to start animation flow.&lt;br&gt;
They get not instanciated manually, but generated by a &lt;a href="https://angular.io/api/core/RendererFactory2" rel="noopener noreferrer"&gt;&lt;strong&gt;RendererFactory2&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Animations module
&lt;/h2&gt;

&lt;p&gt;First step to start using animations is importing &lt;a href="https://angular.io/api/platform-browser/animations/BrowserAnimationsModule" rel="noopener noreferrer"&gt;&lt;strong&gt;BrowserAnimationsModule&lt;/strong&gt;&lt;/a&gt;.&lt;br&gt;
This module, among other things, will provide some concrete implementations of aforementioned abstract classes, adding animation capabilities to component creation logic.&lt;br&gt;
Above all, it will ship &lt;a href="https://github.com/angular/angular/blob/main/packages/platform-browser/animations/src/animation_renderer.ts" rel="noopener noreferrer"&gt;&lt;strong&gt;AnimationRendererFactory&lt;/strong&gt;&lt;/a&gt; that, together with some &lt;strong&gt;Renderer&lt;/strong&gt; implementations it's capable to return, will supersede the ones provided by &lt;strong&gt;BrowserModule&lt;/strong&gt;.&lt;br&gt;
(For the sake of simplicty this series will take in account only the Browser platform, used to build webapps).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;instantiateRendererFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DomRendererFactory2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AnimationEngine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;zone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NgZone&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AnimationRendererFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;zone&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SHARED_ANIMATION_PROVIDERS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AnimationBuilder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BrowserAnimationBuilder&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AnimationStyleNormalizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useFactory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;instantiateDefaultStyleNormalizer&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AnimationEngine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;InjectableAnimationEngine&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RendererFactory2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;useFactory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;instantiateRendererFactory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;DomRendererFactory2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;AnimationEngine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NgZone&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  AnimationRendererFactory creating animation renderer
&lt;/h2&gt;

&lt;p&gt;The gist of this factory is that it gets injected with an &lt;a href="https://github.com/angular/angular/blob/f58ad86e51817f83ff18db790a347528262b850b/packages/animations/browser/src/render/animation_engine_next.ts#L22" rel="noopener noreferrer"&gt;&lt;strong&gt;AnimationEngine&lt;/strong&gt;&lt;/a&gt; used by its generated renderers to enrich DOM operations with animated effects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AnimationRendererFactory&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;RendererFactory2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;delegate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RendererFactory2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AnimationEngine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;_zone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NgZone&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another important dependency passed to its constructor, is the property called &lt;strong&gt;delegate&lt;/strong&gt; typed as &lt;strong&gt;RendererFactory2&lt;/strong&gt;, populated with an instance of &lt;a href="https://github.com/angular/angular/blob/main/packages/platform-browser/src/dom/dom_renderer.ts#L70" rel="noopener noreferrer"&gt;&lt;strong&gt;DomRendererFactory2&lt;/strong&gt;&lt;/a&gt;.&lt;br&gt;
This is an implementation of &lt;a href="https://en.wikipedia.org/wiki/Delegation_pattern" rel="noopener noreferrer"&gt;&lt;strong&gt;Delegation Pattern&lt;/strong&gt;&lt;/a&gt; used to compose an enhanced &lt;em&gt;RendererFactory&lt;/em&gt;.&lt;br&gt;
Normal non-animated DOM operations will be delegated to the original &lt;strong&gt;DefaultDomRenderer2&lt;/strong&gt; instances generated by this delegate factory, while the new &lt;em&gt;delegator&lt;/em&gt; animated renderers will take care of animation tasks only.&lt;/p&gt;

&lt;p&gt;Being this class a factory of renderers, its main functionalities reside in &lt;a href="https://github.com/angular/angular/blob/main/packages/platform-browser/animations/src/animation_renderer.ts#L44" rel="noopener noreferrer"&gt;&lt;strong&gt;createRenderer&lt;/strong&gt;&lt;/a&gt; method.&lt;br&gt;
It accepts two arguments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;strong&gt;hostElement&lt;/strong&gt; being the "first ancestor" of all the elements included in our template (think of the element identified by your component's selector)&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;type&lt;/strong&gt; typed as &lt;a href="https://angular.io/api/core/RendererType2" rel="noopener noreferrer"&gt;&lt;strong&gt;RendererType2&lt;/strong&gt;&lt;/a&gt; (I know... sorry), an object storing some rendering information, mostly retrieved from your &lt;code&gt;@Component&lt;/code&gt; decorator's metadata.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Looking at its early lines we can understand how a basic animation renderer is created for components &lt;strong&gt;not registering any animation&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;createRenderer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hostElement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RendererType2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Renderer2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;EMPTY_NAMESPACE_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// cache the delegates to find out which cached delegate can&lt;/span&gt;
  &lt;span class="c1"&gt;// be used by which cached renderer&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;delegate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;delegate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRenderer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hostElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;hostElement&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;animation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BaseAnimationRenderer&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_rendererCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;delegate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Ensure that the renderer is removed from the cache on destroy&lt;/span&gt;
      &lt;span class="c1"&gt;// since it may contain references to detached DOM nodes.&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onRendererDestroy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_rendererCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;delegate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;renderer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
          &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BaseAnimationRenderer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;EMPTY_NAMESPACE_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delegate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onRendererDestroy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="c1"&gt;// only cache this result when the base renderer is used&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_rendererCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;delegate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;first it uses the factory delegate to generate a pure "animation-unaware" &lt;em&gt;DOMRenderer&lt;/em&gt; and store it as a local &lt;code&gt;delegate&lt;/code&gt; variable
(don't get confused: global delegate &lt;code&gt;this.delegate&lt;/code&gt; refers to &lt;strong&gt;factory delegate&lt;/strong&gt;, while (unfortunately) homonymous local &lt;code&gt;const delegate&lt;/code&gt; point to the newly generated &lt;strong&gt;renderer delegate&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;it checks for any trigger listed inside &lt;strong&gt;animations&lt;/strong&gt; property of &lt;em&gt;@Component&lt;/em&gt;'s decorator
(after verifying the creation request is not relative to an &lt;em&gt;hostRenderer&lt;/em&gt;, but this detail is beyond the scope of this article), and the branch entered when it can't find anyone is the one we're investigating&lt;/li&gt;
&lt;li&gt;looks inside factory cache for an &lt;em&gt;AnimationRenderer&lt;/em&gt; bound to the &lt;em&gt;DOMRenderer&lt;/em&gt; just created (delegate &lt;em&gt;DomRendererFactory2&lt;/em&gt; is capable of returning cached &lt;em&gt;DOMRenderer&lt;/em&gt; too, so the "created" could be a reference to an already existing one, thus giving a match in strict equality lookup used by JS for &lt;em&gt;Map.prototype&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;if not found, creates a new one (injected with freshly created &lt;strong&gt;renderer delegate&lt;/strong&gt;, and with a cache cleanup callback to be issued on renderer destruction), adds that to cache and returns it&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Little work for BaseAnimationRenderer
&lt;/h2&gt;

&lt;p&gt;Looking at &lt;a href="https://github.com/angular/angular/blob/main/packages/platform-browser/animations/src/animation_renderer.ts#L140" rel="noopener noreferrer"&gt;&lt;strong&gt;BaseAnimationRenderer&lt;/strong&gt;&lt;/a&gt; code we notice how for most of its implementations it merely calls the corresponding &lt;em&gt;delegated renderer&lt;/em&gt; methods, aside from elements insertions and deletions related ones.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BaseAnimationRenderer&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Renderer2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nx"&gt;namespaceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;delegate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Renderer2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AnimationEngine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;_onDestroy&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

  &lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newChild&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;delegate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newChild&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onInsert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;namespaceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newChild&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;insertBefore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newChild&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;refChild&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isMove&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;delegate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertBefore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newChild&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;refChild&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// If `isMove` true than we should animate this insert.&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onInsert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;namespaceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newChild&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isMove&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;removeChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;oldChild&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isHostElement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onRemove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;namespaceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;oldChild&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;delegate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isHostElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This seems to be needed by deep layers of animation module to mark the elements as removed or inserted even in absence of a visible transition, mainly for move operations.&lt;br&gt;
More interesting are the overrides of its child class &lt;strong&gt;AnimationRenderer&lt;/strong&gt;, instanciated by the factory when the component that's gonna be created declares some animation triggers.&lt;br&gt;
Both trigger registrations and added functionalities will be covered in following articles.&lt;/p&gt;

&lt;p&gt;Thanks for reading, and feel free to get in touch in comments for every question, correction, clarification or opinion.  &lt;/p&gt;

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