<?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: Ilir Beqiri</title>
    <description>The latest articles on DEV Community by Ilir Beqiri (@lilbeqiri).</description>
    <link>https://dev.to/lilbeqiri</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%2F270881%2F4bb94c9e-a333-4ed6-9a29-ae5a0c2c27c6.jpg</url>
      <title>DEV Community: Ilir Beqiri</title>
      <link>https://dev.to/lilbeqiri</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lilbeqiri"/>
    <language>en</language>
    <item>
      <title>Angular @let declarations: Smart Template Subscriptions</title>
      <dc:creator>Ilir Beqiri</dc:creator>
      <pubDate>Mon, 02 Sep 2024 18:23:07 +0000</pubDate>
      <link>https://dev.to/playfulprogramming-angular/angular-let-declarations-smart-template-subscriptions-4d4h</link>
      <guid>https://dev.to/playfulprogramming-angular/angular-let-declarations-smart-template-subscriptions-4d4h</guid>
      <description>&lt;p&gt;For some time now, Angular has been living in its momentum and the Angular team has proven that it cares about its community. In the Angular v17, and the following minor releases, the Angular team delivered many great features, with one that stood out most, even though in the developer preview, was the new built-in &lt;strong&gt;block&lt;/strong&gt; template syntax that simplified working with templates.&lt;/p&gt;

&lt;p&gt;In the recent version, two long-awaited issues in the Angular repo were closed. Angular major version, v18, shipped the &lt;a href="https://github.com/angular/angular/issues/10887" rel="noopener noreferrer"&gt;Unified Control State Change Events&lt;/a&gt; amongst other features, and the minor version, v18.1, took advantage of the &lt;strong&gt;block&lt;/strong&gt; template syntax by adding a new built-in feature to the template known as the &lt;strong&gt;&lt;a href="https://github.com/angular/angular/issues/15280" rel="noopener noreferrer"&gt;Template Local Variables&lt;/a&gt;&lt;/strong&gt;, denoted by &lt;strong&gt;@let&lt;/strong&gt; block.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Check the official blog &lt;a href="https://blog.angular.dev/introducing-let-in-angular-686f9f383f0f" rel="noopener noreferrer"&gt;post&lt;/a&gt; to know more about how &lt;strong&gt;@let&lt;/strong&gt; variables are defined, work, limitations, and how they update their values.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In simple terms, &lt;strong&gt;Template Local Variables&lt;/strong&gt;, allow Angular developers to declare variables in their templates, just like we do in the component’s class, streamlining how we write the logic in the template thereby bringing alternatives to some old template patterns, and introducing new use cases that were covered in this &lt;a href="https://justangular.com/blog/template-local-variables-with-let-in-angular" rel="noopener noreferrer"&gt;article&lt;/a&gt; from &lt;a class="mentioned-user" href="https://dev.to/eneajaho"&gt;@eneajaho&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The motivation for this article came from a Reddit &lt;a href="https://www.reddit.com/r/Angular2/comments/1e0i5in/why_use_let/?share_id=pVVU1cB1Ij8y7i3A0QKuw&amp;amp;utm_content=1&amp;amp;utm_medium=ios_app&amp;amp;utm_name=ioscss&amp;amp;utm_source=share&amp;amp;utm_term=1" rel="noopener noreferrer"&gt;thread&lt;/a&gt; questioning whether &lt;strong&gt;@let&lt;/strong&gt; declarations were needed and why they should be used.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can find the take of the main Angular contributor, &lt;a href="https://riegler.fr/" rel="noopener noreferrer"&gt;Matthieu Riegler&lt;/a&gt;, about this topic &lt;a href="https://www.youtube.com/shorts/kBFxGrjLSYw" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this article, I want to show a use case of these &lt;strong&gt;local template variables&lt;/strong&gt; I found useful on a project I work on, where I need no more do the “caching” with the RxJS &lt;strong&gt;shareReplay&lt;/strong&gt; operator from the component’s class for using same piece of data in different template sections.&lt;/p&gt;

&lt;p&gt;Let’s dive in 🚀.&lt;/p&gt;




&lt;h2&gt;
  
  
  RxJS “caching” with shareReplay operator
&lt;/h2&gt;

&lt;p&gt;While developing web applications, the most common thing developers do is make HTTP requests. In Angular, HTTP communication is done through an observable-based API, the popular &lt;strong&gt;HttpClient&lt;/strong&gt;. Since in most cases, the fetched data are bound in the template, developers follow the declarative approach with &lt;strong&gt;Async&lt;/strong&gt; pipe as the best practice — automatically subscribes to the observable in the template, and unsubscribes when the component is destroyed 👇:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
@Component({
  ...
  template: `
    ...
    &amp;lt;main&amp;gt;
      ...            👇
      @if (todo$ | async; as todo) {
        &amp;lt;p&amp;gt;Title: {{todo.title}}&amp;lt;/p&amp;gt;
      }
    &amp;lt;/main&amp;gt;
   ...
  `,
  standalone: true,
  ...
})
export class ShareReplayComponent {
  todo$ = inject(HttpClient)
    .get&amp;lt;Todo&amp;gt;('https://jsonplaceholder.typicode.com/todos/1');
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But there are cases when we need the data from the same stream somewhere else in the template, so we bind the observable stream in the template with the &lt;strong&gt;Async&lt;/strong&gt; pipe again 👇:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
@Component({
  template: `
    ...
    &amp;lt;main&amp;gt;
      ...           👇
      @if (todo$ | async; as todo) {
        &amp;lt;p&amp;gt;Title: {{todo.title}}&amp;lt;/p&amp;gt;
      }
    &amp;lt;/main&amp;gt;

    &amp;lt;aside&amp;gt;
      ...            👇
      @if (todo$ | async; as todo) {
        &amp;lt;p&amp;gt;Is Completed: {{todo.completed}}&amp;lt;/p&amp;gt;
      }
    &amp;lt;/aside&amp;gt;
   ...    
  `,
  standalone: true,
})
export class ShareReplayComponent {
  todo$ = inject(HttpClient)
    .get&amp;lt;Todo&amp;gt;('https://jsonplaceholder.typicode.com/todos/1');
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This results in having the same observable stream bound and subscribed in two different sections of the template thus having two, duplicate HTTP requests ongoing for fetching the same piece of data unnecessarily 👇:&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%2Fasz8bi47186p1ggr3c01.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%2Fasz8bi47186p1ggr3c01.gif" alt="Duplicate HTTP requests for the same observable stream bound twice in the template&amp;lt;br&amp;gt;
" width="884" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A common solution to this case (I’ve seen) is caching the data from the first fired HTTP request using RxJS through the &lt;strong&gt;shareReplay&lt;/strong&gt; operator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
@Component({
  template: `
    ...
    &amp;lt;main&amp;gt;
      ...            👇
      @if (todo$ | async; as todo) {
        &amp;lt;p&amp;gt;Title: {{todo.title}}&amp;lt;/p&amp;gt;
      }
    &amp;lt;/main&amp;gt;

    &amp;lt;aside&amp;gt;
      ...            👇
      @if (todo$ | async; as todo) {
        &amp;lt;p&amp;gt;Is Completed: {{todo.completed}}&amp;lt;/p&amp;gt;
      }
    &amp;lt;/aside&amp;gt;
   ...
  `,
  standalone: true,

})
export class ShareReplayComponent {
  todo$ = inject(HttpClient)
    .get&amp;lt;Todo&amp;gt;('https://jsonplaceholder.typicode.com/todos/1')
    .pipe(shareReplay(1)); 👈
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures that even though the same observable stream is bound and subscribed with the &lt;strong&gt;Async&lt;/strong&gt; pipe in several places in the template, only one HTTP request will be triggered, and the response data gets cached 👇:&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%2F2ws0ubgof0rs8xd8oyak.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%2F2ws0ubgof0rs8xd8oyak.gif" alt="Caching HTTP request data with shareReplay RxJS operator" width="800" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This pattern works fine but can we achieve this functionality more simply?&lt;/p&gt;

&lt;p&gt;Let’s find out 💪.&lt;/p&gt;

&lt;h2&gt;
  
  
  @let declarations for streamlining
&lt;/h2&gt;

&lt;p&gt;Although the RxJS solution works fine and fulfills our needs, the &lt;strong&gt;@let&lt;/strong&gt; declarations introduced in Angular v18.1 offer a simpler, template-based alternative 👇:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
@Component({
  template: `
    ...
    @let todo = todo$ | async; 👈
    &amp;lt;main&amp;gt;
      ...
      @if (todo) {
        &amp;lt;p&amp;gt;Title: {{todo.title}}&amp;lt;/p&amp;gt;
      }
    &amp;lt;/main&amp;gt;

    &amp;lt;aside&amp;gt;
      ...
      @if (todo) {
        &amp;lt;p&amp;gt;Is Completed: {{todo.completed}}&amp;lt;/p&amp;gt;
      }
    &amp;lt;/aside&amp;gt;
   ...
  `,
  standalone: true,

})
export class LetVariablesComponent {
  todo$ = inject(HttpClient)
    .get&amp;lt;Todo&amp;gt;('https://jsonplaceholder.typicode.com/todos/1');
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As can be noticed, it offers a kind of “template-based caching” — bind and subscribe to the HTTP request observable only once in the template 👇:&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%2F58nv6zs6gka0s5crw9tz.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%2F58nv6zs6gka0s5crw9tz.gif" alt="Avoid duplicate HTTP requests using @let local variables" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a result, no duplicate HTTP requests are outgoing, and no RxJS caching through the &lt;strong&gt;shareReplay&lt;/strong&gt; operator is required. 🚀🚀&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note💡: This solution works when caching data for the template. The &lt;strong&gt;shareReplay&lt;/strong&gt; operator is required if cached data is needed in the component’s class.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Special thanks to &lt;a class="mentioned-user" href="https://dev.to/kreuzerk"&gt;@kreuzerk&lt;/a&gt; and &lt;a class="mentioned-user" href="https://dev.to/eneajaho"&gt;@eneajaho&lt;/a&gt;  for the review.&lt;/p&gt;

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

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

&lt;p&gt;I hope you enjoyed it 🙌. If you liked the article please share it with your friends and colleagues.&lt;/p&gt;

&lt;p&gt;For any questions or suggestions, feel free to comment below 👇.&lt;/p&gt;

&lt;p&gt;If this article is interesting and useful to you, and you don’t want to miss future articles, follow me at &lt;a href="https://twitter.com/lilbeqiri" rel="noopener noreferrer"&gt;@lilbeqiri&lt;/a&gt;, &lt;a href="https://dev.to/ilirbeqirii"&gt;dev.to&lt;/a&gt;, or &lt;a href="http://lilbeqiri.medium.com/" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;. 📖&lt;/p&gt;

</description>
      <category>angular</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Model Inputs: Reactive Two-Way Binding</title>
      <dc:creator>Ilir Beqiri</dc:creator>
      <pubDate>Wed, 28 Feb 2024 17:54:42 +0000</pubDate>
      <link>https://dev.to/playfulprogramming-angular/model-inputs-reactive-two-way-binding-2538</link>
      <guid>https://dev.to/playfulprogramming-angular/model-inputs-reactive-two-way-binding-2538</guid>
      <description>&lt;p&gt;In Angular v17, the Angular team announced that signals graduated from the developer preview (except effects) as a stable and new reactivity primitive in the framework. Shortly after that, a high-level plan was published by the core members of the Angular team on a meetup (&lt;a href="https://docs.google.com/presentation/d/1oc5dO40VANfkmYMFtyz6rstrJdHqV6nOwJluMjIcCkQ/edit#slide=id.g1e556043fbc_0_0" rel="noopener noreferrer"&gt;#NgGlühwein&lt;/a&gt;), showing the concrete, incremental steps that will follow to gradually integrate signals throughout the framework APIs that they best fit in and take advantage of 👇:&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%2Fxq735mk00o6lpstejkr9.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%2Fxq735mk00o6lpstejkr9.png" alt="Angular Reactivity Plan" width="800" height="500"&gt;&lt;/a&gt;&lt;br&gt;
Then, not a while later, the team revealed publicly the &lt;a href="https://github.com/orgs/angular/projects/31/views/2" rel="noopener noreferrer"&gt;reactivity roadmap&lt;/a&gt;, where you can track all the tiny steps the team is taking to fulfill each of the defined points shown in the plan above.&lt;/p&gt;

&lt;p&gt;With the signals already stable on v17, the focus shifted to the second step in the plan: &lt;strong&gt;Signal I/O&lt;/strong&gt;. The next two minor releases, Angular v17.1, and v17.2 released a few weeks ago, beyond the fact that they were minor releases, they have made a big splash in the community with the new signal APIs introduced in the framework:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;input signals,&lt;/li&gt;
&lt;li&gt;signal queries, and&lt;/li&gt;
&lt;li&gt;model inputs.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;You can read more about these APIs in the official blog &lt;a href="https://blog.angular.io/angular-v17-2-is-now-available-596cbe96242d" rel="noopener noreferrer"&gt;post&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those APIs integrate signals in nearly all component "APIs", leveraging the benefits they offer, thus paving the path to future signal-based components and zoneless change detection.&lt;/p&gt;

&lt;p&gt;Both, &lt;code&gt;signal queries&lt;/code&gt; and &lt;code&gt;signal inputs&lt;/code&gt;, as per the name, provide a reactive, alternative API to decorator-based counterparts, and &lt;code&gt;model inputs&lt;/code&gt; provide a reactive, alternative API for two-way data binding in Angular.&lt;/p&gt;

&lt;p&gt;Currently, in the developer preview, those APIs will be recommended to be used once they are promoted to production-ready APIs in an upcoming version.&lt;/p&gt;

&lt;p&gt;In this article, I will focus on model inputs, as a reactive alternative of two-way binding, and get to know the bonus feature introduced unexpectedly alongside them.&lt;/p&gt;

&lt;p&gt;Let's dive in 🚀&lt;/p&gt;
&lt;h2&gt;
  
  
  Two-Way Binding
&lt;/h2&gt;

&lt;p&gt;For many years now, two-way binding has been the simplest form of parent-child component communication in Angular. It is also widely known as &lt;strong&gt;banana-in-the-box&lt;/strong&gt; - an illustrative name for the template syntactic sugar. Most of the time when we talk about two-way binding in Angular, we all think about the popular &lt;strong&gt;ngModel&lt;/strong&gt; form directive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  selector: 'app-root',
  template: `
    // [(banana-in-the-box)]
               👇
    &amp;lt;input [(ngModel)]="name" /&amp;gt;
  `,
})
export class AppComponent {
  name = '';
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a nutshell, two-way binding is a combination of property and event binding for bidirectional communication between components. Before &lt;code&gt;model inputs&lt;/code&gt;, this two-way communication was possible through the decorator-based APIs, specifically @Input and @Output decorators as below 👇:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// child.component.ts
@Component({
  selector: 'app-child',
  ...
})
export class ChildComponent {
  @Input()
  counter: number = 0;

  @Output()
  counterChange = new EventEmitter&amp;lt;number&amp;gt;();

  changeValue(newValue: number) {
    this.counterChange.emit(newValue)
  }
}

// parent.component.ts
@Component({
  selector: 'app-parent',
  template: `
    // [(banana-in-the-box)]
                    👇
    &amp;lt;app-child [(counter)]="currentCount" /&amp;gt;
  `,
})
export class ParentComponent {
  currentCount = 0;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, you can see that we only define the respective input and output properties but do not define an explicit relationship between them. The compiler is smart enough to detect the relationship through a naming convention: &lt;strong&gt;the @Output property must use the Change naming pattern where the  is the name of the @Input property&lt;/strong&gt;. If we check the compiled code for the implementation above before &lt;code&gt;model inputs&lt;/code&gt;, it looks like the below 👇:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ParentComponent.cmp = /* @__PURE__ */ defineComponent({ type: _ParentComponent, selectors: [["app-parent"]], standalone: true, features: [StandaloneFeature], decls: 1, vars: 1, consts: [[3, "counter", "counterChange"]], template: function ParentComponent_Template(rf, ctx) {
  if (rf &amp;amp; 1) {
    elementStart(0, "app-child", 0);
 👉 listener("counterChange", function ParentComponent_Template_app_child_counterChange_0_listener($event) {
      return ctx.currentCount = $event;
    });
    elementEnd();
  }
  if (rf &amp;amp; 2) {  👇
    property("counter", ctx.currentCount);
  }
}, dependencies: [ChildComponent], styles: ["\n\n/*# sourceMappingURL=parent.component.css.map */"] });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can barely notice two functions of great importance: the &lt;code&gt;property&lt;/code&gt; template instruction which binds the &lt;strong&gt;currentCount&lt;/strong&gt; field to the &lt;strong&gt;counter&lt;/strong&gt; input property, and the &lt;code&gt;listener&lt;/code&gt; template instruction sets up an event and registers a listener which when executed updates the bound field's value.&lt;/p&gt;

&lt;p&gt;This way, components on both ends are aware when the bound value changes but other logic in the component can't implicitly react to this change unless some manual work is done there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// child.component.ts
@Component({
  selector: 'app-child',
  ...
})
export class ChildComponent {
  // using a setter
  _counter: number = 0;
  @Input()
  set counter(counter: number) { 👈
     this._counter = counter;
  }

  @Output()
  counterChange = new EventEmitter&amp;lt;number&amp;gt;();

  ...
}

// parent.component.ts
@Component({
  selector: 'app-parent',
  template: `
    // use standard property/event binding instead                    
    &amp;lt;app-child 
      [counter]="currentCount" 👈
      (counterChange)="onCounterChange($event)" /&amp;gt; 👈
  `,
})
export class ParentComponent {
  currentCount = 0;

  onCounterChange(value: number) {...}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, on the child end, a &lt;strong&gt;setter&lt;/strong&gt; input is used to react whenever the bound value changes, and on the parent end, the banana-in-the-box syntax is replaced with the standard &lt;strong&gt;property&lt;/strong&gt; and &lt;strong&gt;event&lt;/strong&gt; binding instead so the parent will be able to listen for the value change and react accordingly.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;strong&gt;ngOnChanges&lt;/strong&gt; lifecycle hook is an alternative to &lt;strong&gt;setter&lt;/strong&gt; inputs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And… there is no issue with this code, it has been proven to work over time, and serve very well.&lt;/p&gt;

&lt;p&gt;Next, let's see what we get with &lt;code&gt;model inputs&lt;/code&gt; 🐱‍🏍.&lt;/p&gt;

&lt;h2&gt;
  
  
  Model Inputs
&lt;/h2&gt;

&lt;p&gt;Introduced in the Angular v17.2 minor release, as an ongoing effort of the Angular team to integrate signals to component I/O APIs, similar to decorator-based APIs, &lt;code&gt;model inputs&lt;/code&gt; enable bidirectional communication between parent and child components. A key difference is that  they provide a functional, signal-based, reactive API but still use the &lt;strong&gt;banana-in-the-box&lt;/strong&gt; syntactic sugar in the template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// child.component.ts
@Component({
  selector: 'app-child',
  ...
})
export class ChildComponent {
  counter= model(0); 👈

  changeValue(newValue: number) {
    this.counter.set(newValue) 👈
  }
}

// parent.component.ts
@Component({
  selector: 'app-parent',
  template: `      👇
    &amp;lt;app-child [(counter)]="currentCount" /&amp;gt;
  `,
})
export class ParentComponent {
  currentCount = 0;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, instead of the developer defining the input and output properties, we call the &lt;code&gt;model()&lt;/code&gt; function. It's the Angular Compiler that recognizes the API internally and defines the event and property bindings thus providing developers with a reactive public API for use. You can check the source code here 👇:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/angular/angular/blob/69948e1256daf969e060c602f950c3c92e4a5e43/packages/compiler-cli/src/transformers/jit_transforms/initializer_api_transforms/model_function.ts#L34" rel="noopener noreferrer"&gt;https://github.com/angular/angular/blob/69948e1256daf969e060c602f950c3c92e4a5e43/packages/compiler-cli/src/transformers/jit_transforms/initializer_api_transforms/model_function.ts#L34&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To fulfill the two-way binding contract, the function returns a &lt;strong&gt;writable&lt;/strong&gt; signal, thus enabling value updates on the events side of the binding. The generated compiler code looks like this 👇:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ParentComponent.cmp = /* @__PURE__ */ defineComponent({ type: _ParentComponent, selectors: [["app-parent"]], standalone: true, features: [StandaloneFeature], decls: 3, vars: 1, consts: [[3, "counter", "counterChange"]], template: function ParentComponent_Template(rf, ctx) {
  if (rf &amp;amp; 1) {
    ... 👇
    twoWayListener("counterChange", function ParentComponent_Template_app_counter_counterChange_2_listener($event) {
      twoWayBindingSet(ctx.currentCount, $event) || (ctx.currentCount = $event);
      return $event;
    });  
  }
  if (rf &amp;amp; 2) {
    advance(2);
    twoWayProperty("counter", ctx.currentCount); 👈
  }
}, dependencies: [CounterComponent], styles: ["\n\n/*# sourceMappingURL=parent.component.css.map */"] });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same naming convention/pattern is followed as before but now by the compiler itself. But in difference with the previous implementation, to achieve this functionality, a pair of new template instructions were introduced: &lt;strong&gt;twoWayProperty&lt;/strong&gt;, and &lt;strong&gt;twoWayListener&lt;/strong&gt; with &lt;strong&gt;twoWayBindingSet&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/angular/angular/commit/3faf3e23d55b3e41cc43c4498393b01440f1cbb7" rel="noopener noreferrer"&gt;https://github.com/angular/angular/commit/3faf3e23d55b3e41cc43c4498393b01440f1cbb7&lt;/a&gt;&lt;br&gt;
If you check the code behind these instructions, one can see they enhance the functionality of existing, &lt;strong&gt;listener&lt;/strong&gt;, and &lt;strong&gt;property&lt;/strong&gt; template instructions, with writable signal handling capabilities.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;twoWayProperty&lt;/strong&gt; instruction uses the same logic as the &lt;strong&gt;property&lt;/strong&gt; instruction but also does an extra check if the bound field is a writable signal or not, and reads the field value accordingly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// compiled code
twoWayProperty("counter", ctx.currentCount); 👈

// implementation
export function ɵɵtwoWayProperty&amp;lt;T&amp;gt;(
    propName: string, value: T|WritableSignal&amp;lt;T&amp;gt;,
    sanitizer?: SanitizerFn|null): typeof ɵɵtwoWayProperty {
  if (isWritableSignal(value)) { 👈
    value = value();
  }

  const lView = getLView();
  const bindingIndex = nextBindingIndex();
  if (bindingUpdated(lView, bindingIndex, value)) {
    const tView = getTView();
    const tNode = getSelectedTNode();
    elementPropertyInternal(
        tView, tNode, lView, propName, value, lView[RENDERER], sanitizer, false);
    ngDevMode &amp;amp;&amp;amp; storePropertyBindingMetadata(tView.data, tNode, propName, bindingIndex);
  }

  return ɵɵtwoWayProperty;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the other hand, the &lt;strong&gt;twoWayListener&lt;/strong&gt; instruction uses the same logic as the &lt;strong&gt;listener&lt;/strong&gt; instruction, sets up the event, and registers an event listener. This listener itself, does not just update the bound field directly but does an extra check if the bound field is a writable signal or not (using &lt;strong&gt;twoWayBindingSet&lt;/strong&gt; instruction), and then updates the field value accordingly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// compiled code
twoWayListener("counterChange", function ParentComponent_Template_app_counter_counterChange_2_listener($event) {
👉 twoWayBindingSet(ctx.currentCount, $event) || (ctx.currentCount = $event);
    return $event;
});

// implementation
export function ɵɵtwoWayBindingSet&amp;lt;T&amp;gt;(target: unknown, value: T): boolean {
  const canWrite = isWritableSignal(target);
  canWrite &amp;amp;&amp;amp; target.set(value);
  return canWrite;
}

export function ɵɵtwoWayListener(
    eventName: string, listenerFn: (e?: any) =&amp;gt; any): typeof ɵɵtwoWayListener {
  const lView = getLView&amp;lt;{}|null&amp;gt;();
  const tView = getTView();
  const tNode = getCurrentTNode()!;
👉listenerInternal(tView, lView, lView[RENDERER], tNode, eventName, listenerFn);
  return ɵɵtwoWayListener;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, in this way, these instructions enable exposing the bound field to the child component as a signal, specifically a writable signal, thus opening doors for all the benefits that signals provide.&lt;/p&gt;

&lt;p&gt;But… if you stop and reason carefully about the implementation, you can find that alongside the &lt;code&gt;model()&lt;/code&gt; function, surprisingly, a featurette (read: small feature) was shipped. What is interesting is that it was announced by one of the Angular stars, &lt;a href="https://twitter.com/Jean__Meche" rel="noopener noreferrer"&gt;Matthieu Riegler&lt;/a&gt; in X 🚀:&lt;/p&gt;

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

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



&lt;/p&gt;

&lt;p&gt;This is what the next section is all about. Let's go 💪.&lt;/p&gt;

&lt;h2&gt;
  
  
  Signal Double Bindings
&lt;/h2&gt;

&lt;p&gt;In the simplest form, this means that: besides JavaScript's primitive values, developers can now bind a writable signal field in the template for two-way binding as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// child.component.ts
@Component({
  selector: 'app-child',
  ...
})
export class ChildComponent {
  counter= model(0); 👈

  changeValue(newValue: number) {
    this.counter.set(newValue) 👈
  }
}

// parent.component.ts
@Component({
  selector: 'app-parent',
  template: `                  👇
    &amp;lt;app-child [(counter)]="currentCount" /&amp;gt;
  `,
})
export class ParentComponent {
  currentCount = signal(0); 👈
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, this leads to the point that a &lt;strong&gt;writable&lt;/strong&gt; signal will work with the &lt;strong&gt;banana-in-the-box&lt;/strong&gt; syntax on any component providing two-way binding.&lt;/p&gt;

&lt;p&gt;Remember the &lt;strong&gt;ngModel&lt;/strong&gt; form directive I mentioned earlier? It works perfectly fine there too. It offers another alternative to working with form controls and ways to react when the control's value changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  selector: 'app-root',
  template: `
    // [(banana-in-the-box)]
               👇
    &amp;lt;input [(ngModel)]="name" /&amp;gt;
  `,
})
export class AppComponent {
  name = signal('inputs');

  👇
  nickName = computed(() =&amp;gt; `model-${this.name()}`)

  constructor() {
    👉 effect(() =&amp;gt; console.log(this.name()))
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this in place, we have a &lt;strong&gt;reactive way of sharing&lt;/strong&gt; the state between parent and child components, and &lt;strong&gt;easier ways to run logic&lt;/strong&gt; on both ends whenever the bound value changes.&lt;/p&gt;

&lt;p&gt;A thing worth noting here is that, unlike the decorator-based approach, the expanded syntax of property/event binding is not supported when binding a writable signal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
@Component({
  selector: 'app-parent',
  template: `
    &amp;lt;app-child 
      [counter]="currentCount" 👈 // Type 'WritableSignal&amp;lt;number&amp;gt;' is not 
      (counterChange)="onCounterChange($event)" /&amp;gt; assignable to type 'number'
  `,
})
export class ParentComponent {
  currentCount = signal(0);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To understand why this happens, let's see the compiled code when binding a non-signal field 👇:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ParentComponent.cmp = /* @__PURE__ */ defineComponent({ type: _ParentComponent, selectors: [["app-parent"]], standalone: true, features: [StandaloneFeature], decls: 1, vars: 1, consts: [[3, "counter", "counterChange"]], template: function ParentComponent_Template(rf, ctx) {
  if (rf &amp;amp; 1) {
    elementStart(0, "app-child", 0);
 👉 listener("counterChange", function ParentComponent_Template_app_child_counterChange_0_listener($event) {
      return ctx.currentCount = $event;
    });
    elementEnd();
  }
  if (rf &amp;amp; 2) {  👇
    property("counter", ctx.currentCount);
  }
}, dependencies: [ChildComponent], styles: ["\n\n/*# sourceMappingURL=parent.component.css.map */"] });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reason behind this compile-time issue is that the classic template instructions, &lt;strong&gt;listener&lt;/strong&gt;, and &lt;strong&gt;property&lt;/strong&gt; are used for the standalone property and event binding in the template, having no extra logic for handling writable signals, thus restricted to using only non-signal fields for binding.&lt;/p&gt;

&lt;p&gt;But it works if you unbox the signal value when property binding for the same reason when binding a non-signal field 👇:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
@Component({
  selector: 'app-parent',
  template: `
    &amp;lt;app-child 
      [counter]="currentCount()" 👈 // unboxing the value
      (counterChange)="onCounterChange($event)" /&amp;gt;
  `,
})
export class ParentComponent {
  currentCount = signal(0);

  onCounterChange(newCount: number) { this.currentCount.set(newCount);}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hope that this is all clear 🤗.&lt;/p&gt;

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

&lt;p&gt;Angular is evolving. Signals, as a framework-wide feature, are gradually being integrated into component APIs, as a part of a well-prepared plan, thus offering developers a better experience and new ways of authoring components, and reacting to state changes. The last two minor releases, v17.1 and v17.2, nearly completed the signal integration to component APIs by &lt;code&gt;model inputs&lt;/code&gt; introducing signal-based two-way binding hence reactively sharing state between parent and child components. With currently introduced features, paving the path toward signal-based components, and zoneless change detection, the Angular community has reason to look forward to exciting future releases.&lt;/p&gt;

&lt;p&gt;Special thanks to &lt;a href="https://dev.to/eneajaho"&gt;Enea Jahollari&lt;/a&gt; and &lt;a href="https://riegler.fr/" rel="noopener noreferrer"&gt;Matthieu Riegler&lt;/a&gt; for the review.&lt;/p&gt;

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

&lt;p&gt;I hope you enjoyed it 🙌. If you liked the article please feel free to share it with your friends and colleagues.&lt;/p&gt;

&lt;p&gt;For any questions or suggestions, feel free to comment below 👇.&lt;/p&gt;

&lt;p&gt;If this article is interesting and useful to you, and you don't want to miss future articles, follow me at &lt;a href="https://twitter.com/lilbeqiri" rel="noopener noreferrer"&gt;@lilbeqiri&lt;/a&gt;, &lt;a href="https://dev.to/ilirbeqirii"&gt;dev.to&lt;/a&gt;, or &lt;a href="https://lilbeqiri.medium.com/" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;. 📖&lt;/p&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Template-Level Lazy Loading in Angular</title>
      <dc:creator>Ilir Beqiri</dc:creator>
      <pubDate>Tue, 13 Feb 2024 15:57:48 +0000</pubDate>
      <link>https://dev.to/playfulprogramming-angular/template-level-lazy-loading-in-angular-4lgm</link>
      <guid>https://dev.to/playfulprogramming-angular/template-level-lazy-loading-in-angular-4lgm</guid>
      <description>&lt;p&gt;Working with a component-based framework such as Angular, you may witness that templates are a crucial building block of components. Thanks to the template's flexibility and the declarative APIs it supports, we can create highly dynamic web applications. In Angular 17, a ton of great features were introduced, and one of great importance is the new &lt;strong&gt;block&lt;/strong&gt; template syntax, known as @-syntax notation, which led to the introduction of a few new APIs in the template.&lt;/p&gt;

&lt;p&gt;These APIs further extend the template's HTML syntax, with the one standing out amongst them, known as &lt;strong&gt;Deferrable Views&lt;/strong&gt;, accessible through the &lt;code&gt;@defer&lt;/code&gt; block.&lt;/p&gt;

&lt;p&gt;Currently in developer preview, &lt;strong&gt;Deferrable Views&lt;/strong&gt;, augment the Angular templates with a declarative, built-in mechanism, that allows us, developers, to specify which template portions - components, directives, pipes, and any associated CSS - to be lazily loaded later when needed.&lt;/p&gt;

&lt;p&gt;In this article, I will not do an in-depth guide to Deferrable Views but I want to show the manual work that the Angular team took away from us, developers, and moved to the framework itself thus allowing us to achieve lazy loading benefits through a declarative template syntax.&lt;/p&gt;

&lt;p&gt;For the showcase, I am going to demo the most often use-case I used to do lazy loading: &lt;strong&gt;below-the-fold&lt;/strong&gt; content, that will be loaded and rendered when in viewport.&lt;/p&gt;

&lt;h2&gt;
  
  
  Showcase requirements
&lt;/h2&gt;

&lt;p&gt;To better understand what we want to showcase here, let's first define the points we want to implement, as the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trigger lazy loading when in the viewport.&lt;/li&gt;
&lt;li&gt;Handle the loading and error state accordingly.&lt;/li&gt;
&lt;li&gt;Handle the flickering issue.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those represent the main, basic points for our showcase, and later afterward we can implement more complex points like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Early triggering of lazy loading using another trigger element.&lt;/li&gt;
&lt;li&gt;Lazy loading of multiple template portions (read: components).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's dive in 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  Classic Template-Level Lazy Loading
&lt;/h2&gt;

&lt;p&gt;Before Angular 17, there were existing imperative APIs that made it possible to create template portions dynamically - components, directives, pipes, and any associated CSS - and were closely similar to the way how Angular internally handles component creation, and manages templates and views. The dependencies planned to be lazily loaded did not need to be present in the template, and we heavily relied on the imperative usage of JavaScript's dynamic imports to asynchronously load their corresponding modules at runtime.&lt;/p&gt;

&lt;p&gt;An advantage of these classic APIs is that you could take different ways of doing lazy loading, so what I will show here is maybe the simplest way of doing it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The sample demo 🐱‍🏍&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As a starting point, let's use the &lt;strong&gt;UserProfile&lt;/strong&gt; component below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  ...
  template: `
    &amp;lt;div class="wrapper"&amp;gt;
      &amp;lt;app-details&amp;gt;&amp;lt;/app-details&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;div class="wrapper wrapper-xl"&amp;gt;
      &amp;lt;app-projects&amp;gt;&amp;lt;/app-projects&amp;gt;
      &amp;lt;app-achievements&amp;gt;&amp;lt;/app-achievements&amp;gt;
    &amp;lt;/div&amp;gt;

    ...
  `,
  imports: [ProjectsComponent, AchievementsComponent]
  ...
})
export class UserProfileComponent {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;Details&lt;/strong&gt; component shows a pretty long description of the user, meanwhile, the &lt;strong&gt;Projects&lt;/strong&gt; and &lt;strong&gt;Achievements&lt;/strong&gt; components render the list of projects and achievements. As a result of the description being very long, those two components are not visible initially to the user, they are out of the viewport 👇:&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%2Fvsrdd1xcha6risxag7r6.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%2Fvsrdd1xcha6risxag7r6.gif" alt="The initial view of the profile page" width="560" height="255"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This kind of content is known as &lt;strong&gt;below-the-fold&lt;/strong&gt; content, and it's a perfect candidate for lazy loading when working toward improving the initial page load and application bundle.&lt;/p&gt;

&lt;p&gt;Initially, we will lazy load only the &lt;strong&gt;Projects&lt;/strong&gt; component, and be sure to fulfill the main, basic points we defined above. By using classic APIs, here's how the template would initially look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type DepsLoadingState = 'NOT_STARTED' | 'IN_PROGRESS' | 'COMPLETE' | 'FAILED';

@Component({
  ...
  template: `
    &amp;lt;div class="wrapper"&amp;gt;
      &amp;lt;app-details&amp;gt;&amp;lt;/app-details&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;div class="wrapper wrapper-xl"&amp;gt;
      &amp;lt;ng-template #contentSlot /&amp;gt; // 👈 insert lazily loaded content here 

      &amp;lt;ng-container *ngIf="depsState$ | async as state"&amp;gt;
        &amp;lt;ng-template *ngIf="state == 'IN_PROGRESS'" [ngTemplateOutlet]="loadingTpl"&amp;gt;&amp;lt;/ng-template&amp;gt;
        &amp;lt;ng-template *ngIf="state == 'FAILED'" [ngTemplateOutlet]="errorTpl"&amp;gt;&amp;lt;/ng-template&amp;gt;
      &amp;lt;/ng-container&amp;gt;

      &amp;lt;ng-template #loadingTpl&amp;gt;
        &amp;lt;app-projects-skeleton /&amp;gt;
      &amp;lt;/ng-template&amp;gt;

      &amp;lt;ng-template #errorTpl&amp;gt;
        &amp;lt;p&amp;gt;Oops, something went wrong!&amp;lt;/p&amp;gt;
      &amp;lt;/ng-template&amp;gt;
    &amp;lt;/div&amp;gt;
    ...
  `,
  imports: [] // 👈 no need to import
  ...
})
export class UserProfileComponent {
  depsState$ = new BehaviorSubject&amp;lt;DepsLoadingState&amp;gt;('NOT_STARTED');
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, components are removed from the template, and not imported in the imports array of component's or NgModule's metadata. Then, we defined the &lt;strong&gt;container or slot&lt;/strong&gt; (template ref &lt;strong&gt;#contentSlot&lt;/strong&gt;) in the template (using &lt;code&gt;ng-template&lt;/code&gt;)  where the lazily loaded content will be inserted.&lt;/p&gt;

&lt;p&gt;Besides these, we have also defined the loading, and error templates (again, using &lt;code&gt;ng-template&lt;/code&gt;) to help mirror the state of the loading dependencies (tracked by &lt;strong&gt;depsState$&lt;/strong&gt; subject) into the template.&lt;/p&gt;

&lt;p&gt;but 🤚… initially, nothing happens, as no code triggers the loading process …😕&lt;/p&gt;

&lt;p&gt;To fulfill the first point - start loading when in the viewport - we need to define a trigger which is nothing more than the action that needs to occur for the loading of &lt;strong&gt;template dependencies&lt;/strong&gt; to start. In our case, we want to show the content when in the viewport (trigger action) but with the initial template, the content is not present. So, we have to define what is going to trigger that action.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The placeholder template for the rescue 💪&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To have some initial content there in the view, let's add a temporary template, that when in the viewport, triggers the loading of desired content. This temporary template is known as a &lt;strong&gt;placeholder&lt;/strong&gt; template 👇:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
template: `
  ...
  &amp;lt;ng-container *ngIf="depsState$ | async as state"&amp;gt;
        &amp;lt;ng-template *ngIf="state == 'NOT_STARTED'" 
          [ngTemplateOutlet]="placeholderTpl"&amp;gt;
        &amp;lt;/ng-template&amp;gt;
        ...
  &amp;lt;/ng-container&amp;gt;

  &amp;lt;ng-template #placeholderTpl&amp;gt;
    &amp;lt;p&amp;gt;Projects List will be rendered here...&amp;lt;/p&amp;gt; // 👈 trigger element
  &amp;lt;/ng-template&amp;gt;
  ...
`
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The placeholder template, also known as the &lt;strong&gt;trigger element&lt;/strong&gt; is defined as a &lt;code&gt;ng-template&lt;/code&gt; because it will be removed after it fires the loading of template dependencies, the &lt;strong&gt;Project&lt;/strong&gt; component in our case.&lt;/p&gt;

&lt;p&gt;Now with the trigger element in place, all that is left is to define the trigger itself which fires the loading when the trigger element (placeholder) enters the viewport. &lt;/p&gt;

&lt;p&gt;For this purpose, we are going to use the &lt;code&gt;IntersectionObserver&lt;/code&gt; Web API. We encapsulate the logic in a directive,  which emits an event whenever the element it is applied on (trigger element) enters the viewport and stops tracking/observing the trigger element afterward, as below 👇:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Directive({
    selector: '[inViewport]',
    standalone: true
})
export class InViewportDirective implements AfterViewInit, OnDestroy {
    private elRef = inject(ElementRef);

    @Output()
    inViewport: EventEmitter&amp;lt;void&amp;gt; = new EventEmitter();

    private observer!: IntersectionObserver;

    ngAfterViewInit() {
        this.observer = new IntersectionObserver((entries) =&amp;gt; {
            const entry = entries[entries.length - 1];
            if (entry.isIntersecting) {
                this.inViewport.emit();
                this.observer.disconnect();
            }
        });

        this.observer.observe(this.elRef.nativeElement)
    }

    ngOnDestroy(): void {
        this.observer.disconnect();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once emitting, it is in the &lt;strong&gt;UserProfile&lt;/strong&gt; component to take care of the loading process next:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  ...
  template: `
    ...
    &amp;lt;div class="wrapper wrapper-xl"&amp;gt;
      ...
      &amp;lt;ng-template #placeholderTpl&amp;gt;
        // 👇 apply directive to the trigger element
        &amp;lt;p (inViewport)="onViewport()"&amp;gt;
            Projects List will be rendered here...
        &amp;lt;/p&amp;gt; 
      &amp;lt;/ng-template&amp;gt;
      ...
    &amp;lt;/div&amp;gt;
    ...
  `,
  imports: [InViewportDirective]
  ...
})
export class UserProfileComponent {
  @ViewChild('contentSlot', { read: ViewContainerRef }) 
  contentSlot!: ViewContainerRef;

  depsState$ = new BehaviorSubject&amp;lt;DepsLoadingState&amp;gt;('NOT_STARTED');

  onViewport() {
    this.depsState$.next('IN_PROGRESS');

    const loadingDep = import("./user/projects/projects.component");
    loadingDep.then(
      c =&amp;gt; {
        this.contentSlot.createComponent(c.ProjectsComponent);
        this.depsState$.next('COMPLETE');
      },
      err =&amp;gt; this.depsState$.next('FAILED')
    )
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To asynchronously load the component, we use JavaScript's dynamic import function, and then update the tracking state following the state of the loading process thus properly mirroring the state in the template too. Since the loading logic is in the component class, we have to query the container/slot in the template and then use it to instantiate and insert the host of the loaded component into the container after it has been loaded, as you can see below 👇:&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%2Fq3ippm5hhollojocqb5v.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%2Fq3ippm5hhollojocqb5v.gif" alt="Lazy Loading of projects with flickering issue" width="600" height="273"&gt;&lt;/a&gt;&lt;br&gt;
And … that's great! We have a working solution. But if you look carefully, one can observe that the &lt;strong&gt;Project&lt;/strong&gt; component is loaded but the placeholder is hardly visible, and the loading template is not rendered at all because projects are rendered. This can happen if the dependencies are loaded quickly, thus implying some sort of flickering when loading is ongoing. &lt;/p&gt;

&lt;p&gt;This leads us to the 3rd main point we defined above, and this can be resolved by coordinating the time when the placeholder and loading template render, as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function delay(timing: number) {
  return new Promise&amp;lt;void&amp;gt;(res =&amp;gt; {
    setTimeout(() =&amp;gt; {
      res()
    }, timing);
  })
}

@Component({...})
export class UserProfileComponent {
  @ViewChild('contentSlot', { read: ViewContainerRef }) 
  contentSlot!: ViewContainerRef;

  depsState$ = new BehaviorSubject&amp;lt;DepsLoadingState&amp;gt;('NOT_STARTED');

  onViewport() {
    // time after the loading template will be rendered
    delay(1000).then(() =&amp;gt; this.depsState$.next('IN_PROGRESS'));

    const loadingDep = import("./user/projects/projects.component");
    loadingDep.then(
      c =&amp;gt; {
        // minimum time to keep the loading template rendered
        delay(3000).then(() =&amp;gt; {
          this.contentSlot.createComponent(c.ProjectsComponent);

          this.depsState$.next('COMPLETE')
        });
      },
      err =&amp;gt; this.depsState$.next('FAILED')
    )
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thus ensuring users a better visual indication of what is happening and a smoother experience 🤗:&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%2Fdr8lxgkx46rl845njtzo.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%2Fdr8lxgkx46rl845njtzo.gif" alt="Lazy Loading of projects without flickering issue" width="560" height="255"&gt;&lt;/a&gt;&lt;br&gt;
We have fulfilled all of the 3 main points we planned to showcase. A complex one but often, a common requirement, is when we want the loading to start a little bit earlier - before the user scrolling makes the placeholder enter the viewport. This means that the trigger element is different from the placeholder template, and another element above in the template has to be used for that purpose, see below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  ...
  template: `
     ...
    // 👇 trigger element somewhere above in the template
    &amp;lt;span (inViewport)="onViewport()"&amp;gt;&amp;lt;/span&amp;gt;

    &amp;lt;div class="wrapper wrapper-xl"&amp;gt;
      &amp;lt;ng-template #contentSlot /&amp;gt; // 

      &amp;lt;ng-container *ngIf="depsState$ | async as state"&amp;gt;
        &amp;lt;ng-template *ngIf="state == 'NOT_STARTED'" [ngTemplateOutlet]="placeholderTpl"&amp;gt;&amp;lt;/ng-template&amp;gt;
        &amp;lt;ng-template *ngIf="state == 'IN_PROGRESS'" [ngTemplateOutlet]="loadingTpl"&amp;gt;&amp;lt;/ng-template&amp;gt;
        &amp;lt;ng-template *ngIf="state == 'FAILED'" [ngTemplateOutlet]="errorTpl"&amp;gt;&amp;lt;/ng-template&amp;gt;
      &amp;lt;/ng-container&amp;gt;

      &amp;lt;ng-template #placeholderTpl&amp;gt;
        &amp;lt;p&amp;gt;Projects List will be rendered here...&amp;lt;/p&amp;gt;
      &amp;lt;/ng-template&amp;gt;
      ...
    &amp;lt;/div&amp;gt;
    ...
  `,
  imports: [InViewportDirective]
  ...
})
export class UserProfileComponent {
  ...
  onViewport() {
    // same implementation as above
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, while the user scrolls down and the trigger element (span) enters the viewport, the loading of dependencies starts, see below:&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%2Fkz73g55hu8xdpcx71w6n.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%2Fkz73g55hu8xdpcx71w6n.gif" alt="Early trigger of lazy loading projects" width="560" height="255"&gt;&lt;/a&gt;&lt;br&gt;
That is easily verified, as you can see the loading message in the view when scrolling to the Projects section of the page. That's great 😎.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lazy loading of multiple components&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The code we wrote is imperative and simple, but we have one last point to fulfill: to lazy load more than one component. To showcase, the &lt;strong&gt;Achievements&lt;/strong&gt; component is ready to be loaded alongside the &lt;strong&gt;Projects&lt;/strong&gt; component.&lt;/p&gt;

&lt;p&gt;There are 2 paths we can follow for this case: either load them separately or together. If we decide to follow the former option, the same work needs to be done as we did for the &lt;strong&gt;Products&lt;/strong&gt; component, and to be fair even though it is simple, it is a pretty amount of work 😁.&lt;/p&gt;

&lt;p&gt;If decide to follow the latter option, little to no changes are required - you need to adjust the loading and placeholder template to reflect the load of both components and adjust the loading logic in the components' class to manage both dependencies. Notice the use of Promise.AllSettled static method to handle the dynamic loading of multiple dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function loadDeps() {
  return Promise.allSettled(
    [
      import("./user/projects/projects.component"),
      import("./user/achievements/achievements.component")
    ]
  );
}

@Component({
  template: `
    &amp;lt;div class="wrapper wrapper-xl"&amp;gt;
      &amp;lt;ng-template #contentSlot /&amp;gt;

      &amp;lt;ng-template #placeholderTpl&amp;gt;
        &amp;lt;p (inViewport)="onViewport()"&amp;gt;
            Projects and Achievements will be rendered here...
        &amp;lt;/p&amp;gt;
      &amp;lt;/ng-template&amp;gt;

      &amp;lt;ng-template #loadingTpl&amp;gt;
        &amp;lt;h2&amp;gt;Projects&amp;lt;/h2&amp;gt;
        &amp;lt;app-projects-skeleton /&amp;gt;

        &amp;lt;h2&amp;gt;Achievements&amp;lt;/h2&amp;gt;
        &amp;lt;app-achievements-skeleton /&amp;gt;
      &amp;lt;/ng-template&amp;gt;
      ...
    &amp;lt;/div&amp;gt;
  `,
})
export class UserProfileComponent {
  ...
  async onViewport() {
    await delay(1000);
    this.depsState$.next('IN_PROGRESS');

    const [projectsLoadModule, achievementsLoadModule] = await loadDeps();
    if (projectsLoadModule.status == "rejected" || achievementsLoadModule.status == "rejected") {
      this.depsState$.next('FAILED');
      return;
    }

    await delay(3000);

    this.contentSlot.createComponent(projectsLoadModule.value.ProjectsComponent);
    this.contentSlot.createComponent(achievementsLoadModule.value.AchievementsComponent);

    this.depsState$.next('COMPLETE');
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we are still using the same template container/slot for inserting the components into the view, so as a result, we get this 👇:&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%2Fs1vtzg4sw9gctyxpbhay.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%2Fs1vtzg4sw9gctyxpbhay.gif" alt="Lazy loading of Projects and Achievements" width="560" height="255"&gt;&lt;/a&gt;&lt;br&gt;
Error handling of dependencies is project-specific and you are free to implement it as you think it works better for you.&lt;/p&gt;

&lt;p&gt;This is all for the classic approach, a considerable amount of work isn't it? Now let's explore the modern approach.&lt;/p&gt;
&lt;h2&gt;
  
  
  Modern Template-Level Lazy Loading: Deferrable Views
&lt;/h2&gt;

&lt;p&gt;Now, let's see how this new, modern API fits our showcase. For consistency's sake, we will use the same &lt;strong&gt;UserProfile&lt;/strong&gt; component, thus having a close comparison with the classic APIs. As the article's introductory section notes, Angular 17 introduced &lt;strong&gt;Deferrable Views&lt;/strong&gt;, a new API that moves the burden of classic APIs from developers to the framework - more specifically, the compiler.&lt;/p&gt;

&lt;p&gt;Remembering the base points defined above, all that is needed to achieve the same result is the following template code 👇:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  ...
  imports: [... ProjectsComponent],
  template: `
    &amp;lt;div class="wrapper"&amp;gt;
       &amp;lt;app-details /&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;div class="wrapper wrapper-xl"&amp;gt;
       @defer (on viewport) {
         &amp;lt;app-projects /&amp;gt;
       } @placeholder {
         &amp;lt;p&amp;gt;Projects will be rendered here...&amp;lt;/p&amp;gt;
       } @loading {
          &amp;lt;app-projects-skeleton /&amp;gt;
       } @error {
          &amp;lt;p&amp;gt;Oops, something went wrong!&amp;lt;/p&amp;gt;
       }
    &amp;lt;/div&amp;gt;
  `
})
export class UserProfileComponent {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Can you notice the template-driven approach? There is no imperative work for state management and async loading, thus having a code-free class component. The content to be lazy-loaded is specified inside the &lt;code&gt;@defer&lt;/code&gt; block and the trigger is defined as a parameter after that (on &lt;strong&gt;viewport&lt;/strong&gt;). Also, you declaratively define the placeholder, error, and loading templates using the naming-relevant template @blocks (no &lt;code&gt;ng-templates&lt;/code&gt;) to properly mirror the state of the process in the template, with the placeholder template being the trigger element:&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%2Fmvteyqpcjv8guy1i6zth.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%2Fmvteyqpcjv8guy1i6zth.gif" alt="Deferrable loading of projects when in the viewport" width="600" height="337"&gt;&lt;/a&gt;&lt;br&gt;
But there is a small detail that you may have spotted already: since the &lt;strong&gt;Project&lt;/strong&gt; component is on the template at the author's time, it needs to be imported into the imports array of the component's metadata just so template dependencies are detectable and reachable. But, the compiler is aware of that, so everything works as it should.&lt;/p&gt;

&lt;p&gt;You may also notice the flickering issue occurring for the same reasons as before. As earlier, to fix it, you need to coordinate the time when either the placeholder or loading template is shown. To accomplish this, the &lt;code&gt;@loading&lt;/code&gt; block accepts two optional params, &lt;strong&gt;minimum&lt;/strong&gt; and &lt;strong&gt;after&lt;/strong&gt;, as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  ...
  template: `
    ...
    &amp;lt;div class="wrapper wrapper-xl"&amp;gt;
       @loading (after 1s; minimum 3s) {
          &amp;lt;app-projects-skeleton /&amp;gt;
       }
    &amp;lt;/div&amp;gt;
    ...
  `
})
export class UserProfileComponent {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The parameters provided to the &lt;code&gt;@loading&lt;/code&gt; block control &lt;strong&gt;when&lt;/strong&gt; and &lt;strong&gt;how&lt;/strong&gt; long it should be rendered on the view. In our case, parameters specify that the &lt;code&gt;@loading&lt;/code&gt; block is to be shown one second after the loading process begins and remain visible for at least three seconds:&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%2Fstb74q9stddol2sxep08.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%2Fstb74q9stddol2sxep08.gif" alt="Deferrable loading of projects with no flickering" width="600" height="273"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;strong&gt;deferrable views&lt;/strong&gt; work only with standalone dependencies.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Triggers themselves are capable of accepting parameters, just like template blocks do. In our scenario, the viewport trigger accepts an optional parameter which is a DOM element that acts as the trigger element ( replacing the placeholder template). This enables dependencies to begin loading before the user scrolls to the area of the page where the loaded content will be rendered:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  ...
  imports: [ProjectsComponent],
  template: `
    ...
    &amp;lt;span #triggerEl&amp;gt;&amp;lt;/span&amp;gt;
    ...

    &amp;lt;div class="wrapper wrapper-xl"&amp;gt;
       @defer (on viewport(triggerEl)) {
         &amp;lt;app-projects /&amp;gt;
       } 
       ...
    &amp;lt;/div&amp;gt;
  `
})
export class UserProfileComponent {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The loading of dependencies now begins as the user scrolls down and the trigger element (span) reaches the viewport, see below 👇:&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%2Fx6wlgkerru5s7ulu0hhe.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%2Fx6wlgkerru5s7ulu0hhe.gif" alt="Early trigger of lazy loading of projects" width="560" height="255"&gt;&lt;/a&gt;&lt;br&gt;
That is easily verified, as you can see the loading template in the view when scrolling to the Projects section of the page. That's great 😎.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lazy loading of multiple components&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Up to now, we still have one last point to fulfill: lazy loading more than one component. To showcase, the &lt;strong&gt;Achievements&lt;/strong&gt; component is ready to be loaded alongside the &lt;strong&gt;Projects&lt;/strong&gt; component.&lt;/p&gt;

&lt;p&gt;As with the classic approach, there are 2 paths to follow: either load them separately or together. With the new API, &lt;code&gt;@defer&lt;/code&gt; block, both of these options are easy to implement 😎.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Loading them together 🚀&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To load components together, the &lt;strong&gt;Achievements&lt;/strong&gt; component needs to be imported to the imports array of component metadata, and then inserted into the &lt;code&gt;@defer&lt;/code&gt; block, as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  ...
  imports: [... ProjectsComponent, AchievementsComponent],
  template: `
     ...

    &amp;lt;div class="wrapper wrapper-xl"&amp;gt;
       @defer (on viewport) {
         &amp;lt;app-projects /&amp;gt;
         &amp;lt;app-achievements /&amp;gt;
       } @placeholder () {
         &amp;lt;p&amp;gt;Projects and Achievements will be rendered here...&amp;lt;/p&amp;gt;
       } @loading (after 1s; minimum 3s) {
          &amp;lt;h2&amp;gt;Projects&amp;lt;/h2&amp;gt;
          &amp;lt;app-projects-skeleton /&amp;gt;

          &amp;lt;h2&amp;gt;Achievements&amp;lt;/h2&amp;gt;
          &amp;lt;app-achievements-skeleton /&amp;gt;
       } @error {
          &amp;lt;p&amp;gt;Oops, something went wrong!&amp;lt;/p&amp;gt;
       }
    &amp;lt;/div&amp;gt;
  `
})
export class UserProfileComponent {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, the loading and placeholder templates are adjusted to reflect the loading of both components and nothing anymore👇:&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%2Fka0g5r8mh14nmda8k68g.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%2Fka0g5r8mh14nmda8k68g.gif" alt="Deferrable loading of projects and achievements" width="600" height="273"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Loading them separately 🚀&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To load components separately, each of them should be wrapped in its &lt;code&gt;@defer&lt;/code&gt; block and define other associated blocks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  ...
  imports: [... ProjectsComponent, AchievementsComponent],
  template: `
     ...

    &amp;lt;div class="wrapper wrapper-xl"&amp;gt;
       @defer (on viewport) {
          &amp;lt;app-projects  /&amp;gt;
       } @placeholder () {
          &amp;lt;p&amp;gt;Projects will be rendered here...&amp;lt;/p&amp;gt;
       } @loading (after 1s; minimum 3s) {
          &amp;lt;h2&amp;gt;Projects&amp;lt;/h2&amp;gt;
          &amp;lt;app-projects-skeleton /&amp;gt;
       } @error {
          &amp;lt;p&amp;gt;Oops, something went wrong!&amp;lt;/p&amp;gt;
       }

       @defer (on viewport) {
          &amp;lt;app-achievements /&amp;gt;
       } @placeholder () {
          &amp;lt;p&amp;gt;Achievements will be rendered here...&amp;lt;/p&amp;gt;
       } @loading (after 1s; minimum 3s) {
          &amp;lt;h2&amp;gt;Achievements&amp;lt;/h2&amp;gt;
          &amp;lt;app-achievements-skeleton /&amp;gt;
       } @error {
          &amp;lt;p&amp;gt;Oops, something went wrong!&amp;lt;/p&amp;gt;
       }
    &amp;lt;/div&amp;gt;
  `
})
export class UserProfileComponent {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compared with the classic approach, far less code is required. You can add as many &lt;code&gt;@defer&lt;/code&gt; blocks as you need with little effort, and still be sure that it works perfectly fine 🤗:&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%2Fiery035gl7nsc03m3k3o.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%2Fiery035gl7nsc03m3k3o.gif" alt="Deferrable loading of projects and achievements (separately)" width="600" height="273"&gt;&lt;/a&gt;&lt;br&gt;
That's all for the modern approach. These are only a handful of the many features that Deferrable View offers. Check out these resources for a more comprehensive guide on deferrable views:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://angular.dev/guide/defer" rel="noopener noreferrer"&gt;Angular Deferrable Views Docs&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Article and Video: &lt;a href="https://angularexperts.io/blog/angular-defer-lazy-loading-total-guide" rel="noopener noreferrer"&gt;Tomas Trajan&lt;/a&gt;, &lt;a href="https://riegler.fr/blog/2023-10-05-defer-part1" rel="noopener noreferrer"&gt;Matthieu Riegler&lt;/a&gt;, &lt;a href="https://www.youtube.com/watch?v=7gCWNAZQGzA" rel="noopener noreferrer"&gt;Fanis Prodromou&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lazy loading is a performance optimization technique adopted in web frameworks like Angular. Route-level lazy loading is very popular in the Angular community but template-level lazy loading is lacking popularity even though time has proven that existing  APIs work very well. The amount of work, involvement of both component's class and template, and all of that imperative code makes them everything but not developer-friendly.&lt;/p&gt;

&lt;p&gt;Angular 17, through the &lt;code&gt;@block&lt;/code&gt; template syntax, deferrable views provide a &lt;strong&gt;modern&lt;/strong&gt;, &lt;strong&gt;declarative&lt;/strong&gt;, &lt;strong&gt;template-driven&lt;/strong&gt; API, that can be used to defer the loading of portions of the template that may not ever be loaded until a future point in time. All you need to do is determine which setup of these APIs best suits your intended use case.&lt;/p&gt;

&lt;p&gt;You can find and play with the final code here: &lt;a href="https://github.com/ilirbeqirii/lazy-load-component" rel="noopener noreferrer"&gt;https://github.com/ilirbeqirii/lazy-load-component&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Special thanks to &lt;a class="mentioned-user" href="https://dev.to/kreuzerk"&gt;@kreuzerk&lt;/a&gt; and &lt;a class="mentioned-user" href="https://dev.to/eneajaho"&gt;@eneajaho&lt;/a&gt; for review.&lt;/p&gt;

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

&lt;p&gt;I hope you enjoyed it 🙌. If you liked the article please feel free to share it with your friends and colleagues.&lt;br&gt;
For any questions or suggestions, feel free to comment below 👇.&lt;br&gt;
If this article is interesting and useful to you, and you don't want to miss future articles, follow me at &lt;a href="https://twitter.com/lilbeqiri" rel="noopener noreferrer"&gt;@lilbeqiri&lt;/a&gt;, &lt;a href="https://dev.to@ilirbeqirii"&gt;dev.to&lt;/a&gt;, or &lt;a href="https://lilbeqiri.medium.com/" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;. 📖&lt;/p&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Local Change Detection in Angular 17</title>
      <dc:creator>Ilir Beqiri</dc:creator>
      <pubDate>Fri, 22 Dec 2023 17:07:23 +0000</pubDate>
      <link>https://dev.to/playfulprogramming-angular/local-change-detection-in-angular-17-5bdj</link>
      <guid>https://dev.to/playfulprogramming-angular/local-change-detection-in-angular-17-5bdj</guid>
      <description>&lt;h2&gt;
  
  
  How to use Angular Signals and OnPush change detection strategy to improve performance with local change detection
&lt;/h2&gt;

&lt;p&gt;For quite some time now, the Angular community has been witnessing a lot of improvements and new features being added to their beloved framework. A few weeks ago, Angular v17 was released introducing a ton of high-quality improvements and features, with signals APIs (except effect()) making their way out of developer preview. With performance always being the discussion topic in the community regarding change detection, stable signal APIs seem to make the framework more powerful and smarter in change detection 🤯.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can read more about Angular v17 in the official blog &lt;a href="https://blog.angular.io/introducing-angular-v17-4d7033312e4b" rel="noopener noreferrer"&gt;post&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Some time ago, the Angular team started working on finding a way to introduce &lt;code&gt;locality&lt;/code&gt; awareness in the framework (when detecting changes) in the sense of figuring out what impact a change of state has on the application thus not depending on Zone.js anymore.&lt;/p&gt;

&lt;p&gt;For this purpose, in Angular v17, conforming to the current Zonejs-based, top-down change detection approach, signals have been fine-tuned, providing a starting point toward locality awareness, thus introducing some sort of what the Angular community calls &lt;strong&gt;Local Change Detection&lt;/strong&gt; 🚀.&lt;/p&gt;

&lt;p&gt;This is a great ability that has been added to the framework through signals and is expected to provide performance gains, but is this what the community has been thriving for? is this going to reduce the amount of checks needed during a change detection cycle? and is it somehow related to change detection strategies?&lt;/p&gt;

&lt;p&gt;In this article, we are going to elaborate and see how that &lt;code&gt;locality&lt;/code&gt; awareness is achieved, conditions for it to be used effectively and properly, and show some working examples. Let's dive in 🐱‍🏍.&lt;/p&gt;

&lt;h3&gt;
  
  
  Change Detection Modes
&lt;/h3&gt;

&lt;p&gt;Before Angular v17, whenever an event happens that Zone.js is &lt;a href="https://itnext.io/a-change-detection-zone-js-zoneless-local-change-detection-and-signals-story-9344079c3b9d" rel="noopener noreferrer"&gt;patching&lt;/a&gt;, which may lead to state changes, Zone.js picks up this event and informs Angular that some state changed (not specifically where) and that it should run change detection. Since Angular does not know where a change comes from or where the change happened, it starts traversing the component tree and dirty-checking the all components. This approach to detect changes is known as the &lt;strong&gt;Global&lt;/strong&gt; mode.&lt;/p&gt;

&lt;p&gt;With signals🚦, this approach is going to be fine-tuned in the sense that no need to dirty-check all the components anymore. Signals can track where they are being consumed. For signals bound on the component template, the template is a consumer, that every time the signal value changes, needs to pull out that new value (hence live consumer). Thus when signal value changes, it is enough to mark its consumers as dirty, but not need the same for ancestor components (as it was pre-v17). For this purpose, a new &lt;a href="https://github.com/angular/angular/pull/52302" rel="noopener noreferrer"&gt;improvement&lt;/a&gt; shipped in the latest version makes signals smart enough to &lt;strong&gt;&lt;a href="https://github.com/angular/angular/blob/d9348be79f61eca32dbb3643507135d5238a2bbd/packages/core/primitives/signals/src/graph.ts#L319" rel="noopener noreferrer"&gt;mark dirty&lt;/a&gt;&lt;/strong&gt; only that specific component it is consumed on (live consumer) and marks ancestor components for &lt;strong&gt;&lt;a href="https://github.com/angular/angular/blob/d9348be79f61eca32dbb3643507135d5238a2bbd/packages/core/src/render3/util/view_utils.ts#L223" rel="noopener noreferrer"&gt;traversal&lt;/a&gt;&lt;/strong&gt; (by adding the &lt;code&gt;HasChildViewsToRefresh&lt;/code&gt; flag).&lt;/p&gt;

&lt;p&gt;To achieve this, a new function &lt;code&gt;markAncestorsForTraversal&lt;/code&gt; is introduced replacing &lt;code&gt;markViewDirty&lt;/code&gt; (which is used to mark dirty also all ancestor components). Let's look at the underlying code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export function consumerMarkDirty(node: ReactiveNode): void {
  node.dirty = true;
  producerNotifyConsumers(node);
  node.consumerMarkedDirty?.(node);
}

consumerMarkedDirty: (node: ReactiveLViewConsumer) =&amp;gt; {
  markAncestorsForTraversal(node.lView!);
},

export function markAncestorsForTraversal(lView: LView) {
  let parent = lView[PARENT];
  while (parent !== null) {
    // We stop adding markers to the ancestors once we reach one that already has the marker. This
    // is to avoid needlessly traversing all the way to the root when the marker already exists.
    if ((isLContainer(parent) &amp;amp;&amp;amp; (parent[FLAGS] &amp;amp; LContainerFlags.HasChildViewsToRefresh) ||
         (isLView(parent) &amp;amp;&amp;amp; parent[FLAGS] &amp;amp; LViewFlags.HasChildViewsToRefresh))) {
      break;
    }

    if (isLContainer(parent)) {
      parent[FLAGS] |= LContainerFlags.HasChildViewsToRefresh;
    } else {
      parent[FLAGS] |= LViewFlags.HasChildViewsToRefresh;
      if (!viewAttachedToChangeDetector(parent)) {
        break;
      }
    }
    parent = parent[PARENT];
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;During change detection (triggered by Zone.js), components marked for &lt;strong&gt;traversal&lt;/strong&gt;, when visited, let Angular understand that they don't need to be checked for changes but that they have dirty children. This way ensures they are accessible during the change detection process even when they are not dirty but skipped on the way to the dirty children which are refreshed. As a result, the new ability of signals to localize where in the component tree the change has occurred provides the "Local" change detection we talked about earlier. The improved approach enforced by signals is known as the &lt;strong&gt;Targeted&lt;/strong&gt; mode of detecting changes. In this mode, Angular still initiates a top-bottom checking process (recall triggered by Zone.js), but now it traverses through components marked for traversal, and targets to refresh only dirty consumers.&lt;/p&gt;

&lt;p&gt;This approach certainly seems to bring performance gains in overall application but do we have it out of the box or is it an opt-in feature?&lt;/p&gt;

&lt;h3&gt;
  
  
  Change Detection Strategies
&lt;/h3&gt;

&lt;p&gt;In general, the best way to address performance concerns is by doing less work, which means, running less code, and in Angular, this means reducing change detection cycles and the number of components being checked for changes during a cycle. To achieve this, Angular needs a way to know which components must or not be checked for changes.&lt;/p&gt;

&lt;p&gt;Since Angular is not able to know exactly which component has changed, and change detection is global, the top-bottom process, assumes that all components in the tree are dirty, and need to be checked for changes on every cycle. This means that components, dirty or not, will be checked for changes. This behavior and conformance of components regarding the change detection process is referred to as a &lt;strong&gt;change detection strategy&lt;/strong&gt;. Since this is the default component behavior, it is known as the &lt;strong&gt;Default&lt;/strong&gt; change detection strategy.&lt;/p&gt;

&lt;p&gt;To improve this behavior, and make Angular do less work, the Angular team introduced a new strategy that reduces the number of components to be checked for changes. This new strategy is known as the &lt;strong&gt;OnPush&lt;/strong&gt; change detection strategy, which allows skipping subtrees of components that are not dirty.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There are 3 criteria when the OnPush component is marked dirty, and you can find more about them in this &lt;a href="https://blog.simplified.courses/angular-change-detection-onpush-or-not/" rel="noopener noreferrer"&gt;article&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, based on this information, we can allude that the OnPush change detection strategy seems to let us benefit from v17's Local change detection. Let's find out if it stands 💪.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hybrid Change Detection
&lt;/h3&gt;

&lt;p&gt;For demo purposes, below is a small reproduction of the app supporting our case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  ...
  selector: 'app-child-y',
  templateUrl: `
    &amp;lt;div class="container"&amp;gt;
      &amp;lt;h3&amp;gt;Child Y&amp;lt;br /&amp;gt; value: {{ count() }} runs: {{getChecked()}}&amp;lt;/h3&amp;gt;

      &amp;lt;app-grandchild-y /&amp;gt;
    &amp;lt;/div&amp;gt;
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  ...
})
export class ChildYComponent {...}

@Component({
  ...
  selector: 'app-child-x',
  templateUrl: `
    &amp;lt;div class="container"&amp;gt;
      &amp;lt;h3&amp;gt;Child X &amp;lt;br /&amp;gt; value: {{ count() }} runs: {{getChecked()}}&amp;lt;/h3&amp;gt;

      &amp;lt;app-grandchild-x /&amp;gt;
    &amp;lt;/div&amp;gt;
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  ...
})
export class ChildXComponent {...}

@Component({
  ...
  selector: 'app-parent',
  templateUrl: `
    &amp;lt;div class="container"&amp;gt;
      &amp;lt;h2&amp;gt;Parent &amp;lt;br /&amp;gt; value: {{count()}} runs: {{getChecked()}}&amp;lt;/h2&amp;gt;

      &amp;lt;div class="children"&amp;gt;
        &amp;lt;app-child-x /&amp;gt;
        &amp;lt;app-child-y /&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  `,
  ...
})
export class ParentComponent {...}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The app visualizes a component tree, with the &lt;strong&gt;Parent&lt;/strong&gt; component having &lt;strong&gt;Default&lt;/strong&gt; change detection, and its two child components, &lt;strong&gt;ChildX&lt;/strong&gt; and &lt;strong&gt;ChildY&lt;/strong&gt; components, each with &lt;strong&gt;OnPush&lt;/strong&gt; change detection, and one child component, &lt;strong&gt;GrandChildX&lt;/strong&gt; component and &lt;strong&gt;GrandChildY&lt;/strong&gt; component respectively, as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  ...
  selector: 'app-grandchild-x',
  templateUrl: `
    &amp;lt;div class="container"&amp;gt;
      &amp;lt;h4&amp;gt;(GrandChild X &amp;lt;br /&amp;gt; value: {{ count() }} runs: {{getChecked()}}&amp;lt;/h4&amp;gt;

      &amp;lt;button (click)="updateValue()"&amp;gt;Increment Count&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  ...
})
export class GrandchildXComponent {
  ...

  updateValue() {
    this.count.update((v) =&amp;gt; v + 1);
  }
}

@Component({
  ...
  selector: 'app-grandchild-y',
  templateUrl: `
    &amp;lt;div class="container" appColor&amp;gt;
      &amp;lt;h4&amp;gt;(GrandChild Y &amp;lt;br /&amp;gt; value: {{ count() }} runs: {{getChecked()}}&amp;lt;/h4&amp;gt;

      &amp;lt;button #incCount&amp;gt;Increment Count&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  ...
})
export class GrandchildYComponent implements AfterViewInit {
  ...

  @ViewChild('incCount') incButton!: ElementRef&amp;lt;HTMLButtonElement&amp;gt;;

  ngZone = inject(NgZone);
  injector = inject(Injector);
  app = inject(ApplicationRef);

  ngAfterViewInit(): void {
    runInInjectionContext(this.injector, () =&amp;gt; {
      this.ngZone.runOutsideAngular(() =&amp;gt; {
        fromEvent(this.incButton.nativeElement, 'click')
          .pipe(throttleTime(1000), takeUntilDestroyed())
          .subscribe(() =&amp;gt; {
            this.count.update((v) =&amp;gt; v + 1);
            this.app.tick();   
          });
      });
    });
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only difference between grandchild components is the way the click event handler is handled. In the following section, we will understand the reason behind this decision.&lt;/p&gt;

&lt;p&gt;Now that on both sides of the component tree, all components are using the &lt;strong&gt;OnPush strategy&lt;/strong&gt;, let's check what happens when incrementing the count at the &lt;strong&gt;GrandChildX&lt;/strong&gt; component:&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%2Fujikvjc9zkhl6wlql3vv.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%2Fujikvjc9zkhl6wlql3vv.gif" alt="Signals and OnPush with click event handler not getting benefits of local change detection in Angular v17" width="756" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What we are witnessing here is no difference as if it was a Global strategy in use. Even though components use the OnPush strategy they are still being checked for changes. Why is this happening?&lt;/p&gt;

&lt;p&gt;Well, Angular internally wraps event listeners in a &lt;a href="https://github.com/angular/angular/blob/18929040704828bf4caf76797ab141ca101c4b5f/packages/core/src/render3/instructions/listener.ts#L244" rel="noopener noreferrer"&gt;function&lt;/a&gt; that marks the component and its ancestors for check when an event happens. In addition, Zone.js monkey-patches the event and notifies Angular when it's fired so that Angular can start change detection. So in our case, when we click the button, it marks current and ancestor components as dirty. And since change detection starts in Global mode, the whole tree is refreshed. This is how change detection used to work before v17  and was left intact for backward compatibility purposes.&lt;/p&gt;

&lt;p&gt;Based on this, we can conclude that to get Local CD benefits, we have to: &lt;strong&gt;update the signal in a way that doesn't mark for checking all the ancestor components.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hmm🤔… okay. We took care of the increment button at the &lt;strong&gt;GrandChildY&lt;/strong&gt; component to respect this requirement (credits &lt;a href="https://twitter.com/laforge_toma" rel="noopener noreferrer"&gt;Thomas Laforge&lt;/a&gt;), so let's see what we get now 👇:&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%2Fu7f0atr5wmj28g0dk5ae.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%2Fu7f0atr5wmj28g0dk5ae.gif" alt="Local Change Detection in Angular v17 with OnPush and Signals" width="756" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And yay 😊. Now we get the local change detection in our application. To be more clear, when the button is clicked, the signal value gets updated, which then marks the current component(consumer) as dirty and the ancestor components for traversal. After that, Zone.js gets triggered (remember monkey-patching) which notifies Angular, then Angular starts change detection in Global mode and refreshes the &lt;strong&gt;Parent&lt;/strong&gt; component because it uses the Default change detection strategy, switches to the Targeted mode when visiting components marked for traversal (with the &lt;code&gt;HasChildViewsToRefresh&lt;/code&gt; flag), and uses the OnPush change detection strategy, &lt;strong&gt;ChildY&lt;/strong&gt; component in this case, traversing them but not refreshing, then finally coming to the dirty &lt;strong&gt;GrandChildY&lt;/strong&gt; component (consumer), switching back to the Global mode of change detection, and refreshing the view. This back-and-forth switching that Angular does between change detection modes, &lt;strong&gt;Global&lt;/strong&gt; and &lt;strong&gt;Targeted&lt;/strong&gt;, is known as &lt;strong&gt;Hybrid change detection&lt;/strong&gt; 🐱‍🏍.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you want to see how this is managed internally, check the &lt;a href="https://github.com/angular/angular/blob/18929040704828bf4caf76797ab141ca101c4b5f/packages/core/src/render3/instructions/change_detection.ts#L376" rel="noopener noreferrer"&gt;source code&lt;/a&gt; at Angular repo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, with all of those things mentioned, someone can say that there seem to be not too many places where we would get the benefits of local change detection. Indeed, we won't get the benefit all over the place, but also the click handling above is not the usual thing we do a lot. But there are other use cases where we can get this benefit (credits &lt;a href="https://twitter.com/Enea_Jahollari" rel="noopener noreferrer"&gt;Enea Jahollari&lt;/a&gt;), see below:&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%2Fp08eousl9r6n2ww3y2y1.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%2Fp08eousl9r6n2ww3y2y1.gif" alt="Shared signal state in a service or ngrx store when changed only OnPush components will be checked, thus we have local change detection" width="756" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here you can see a more usual case, where you have some shared state in service, a typical case being state management libraries (NgRx, Akita, …), and that piece of state is being used in many components throughout the component tree. Also, the case of having some state on the parent component that can be consumed from child components. When this state (remember a signal value ⚠) changes, only the components that consume (consumers) the state are marked dirty, and with the OnPush CD strategy set on, you will get the benefits of local change detection.&lt;/p&gt;

&lt;p&gt;This is a typical use case to mention and, if you have in mind other use cases where we can benefit from local change detection, feel free to share them with me and the community.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Improving change detection has always been one of the priorities of the Angular team and community. This kind of locality that we have now in v17 is not the complete one but it represents a good start and initial step toward what is expected to be delivered on future versions. Even though not provided out of the box, developers can leverage local change detection benefits in their apps with a few adjustments: &lt;strong&gt;OnPush change detection strategy and Signals&lt;/strong&gt;. To know more what's the Angular team's plan regarding reactivity, check the released &lt;a href="https://github.com/orgs/angular/projects/31" rel="noopener noreferrer"&gt;roadmap&lt;/a&gt; 🔥.&lt;/p&gt;

&lt;p&gt;Here is a visualization of all that was presented in the article:&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%2F6h731f9dhxawwcc18c8a.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%2F6h731f9dhxawwcc18c8a.png" alt="Visual presentation of local change detection in Angular v17" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find and play with the final code here: &lt;a href="https://stackblitz.com/edit/local-cd-angular-17?file=src%2Fmain.ts" rel="noopener noreferrer"&gt;https://stackblitz.com/edit/local-cd-angular-17?file=src%2Fmain.ts&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/local-cd-angular-17?embed=1&amp;amp;file=src%2Fmain.ts" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Resources
&lt;/h3&gt;

&lt;p&gt;If you want to read more about local change detection in v17 make sure you check these &lt;a href="https://gist.github.com/ilirbeqirii/e788465afc829398df1fa97ef4e5d1dc" rel="noopener noreferrer"&gt;resources&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Special thanks to &lt;a class="mentioned-user" href="https://dev.to/kreuzerk"&gt;@kreuzerk&lt;/a&gt;, &lt;a class="mentioned-user" href="https://dev.to/eneajaho"&gt;@eneajaho&lt;/a&gt;, &lt;a class="mentioned-user" href="https://dev.to/tomastrajan"&gt;@tomastrajan&lt;/a&gt;, and &lt;a href="https://twitter.com/Jean__Meche" rel="noopener noreferrer"&gt;Matthieu Riegler&lt;/a&gt; for review.&lt;/p&gt;

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

&lt;p&gt;I hope you enjoyed it 🙌. If you liked the article please feel free to share it with your friends and colleagues.&lt;br&gt;
For any questions or suggestions, feel free to comment below 👇.&lt;br&gt;
If this article is interesting and useful to you, and you don't want to miss future articles, follow me at &lt;a href="https://twitter.com/lilbeqiri" rel="noopener noreferrer"&gt;@lilbeqiri&lt;/a&gt;, &lt;a href="https://dev.to@ilirbeqirii"&gt;dev.to&lt;/a&gt;, or &lt;a href="https://lilbeqiri.medium.com/" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;. 📖&lt;/p&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>performance</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Declarative Loop Control Flow in Angular 17</title>
      <dc:creator>Ilir Beqiri</dc:creator>
      <pubDate>Fri, 20 Oct 2023 18:01:43 +0000</pubDate>
      <link>https://dev.to/playfulprogramming-angular/declarative-loop-control-flow-in-angular-17-97d</link>
      <guid>https://dev.to/playfulprogramming-angular/declarative-loop-control-flow-in-angular-17-97d</guid>
      <description>&lt;p&gt;In the last few releases, a relatively short time, we witnessed a lot of additions and improvements to the Angular framework, and the future seems to be no worse. Angular Renaissance or Momentum, the next version (v17) will come with some more high qualitative improvements, one amongst them being the new built-in &lt;strong&gt;Control Flow Template Syntax&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;As the name suggests, this improvement, introduces the &lt;strong&gt;built-in&lt;/strong&gt; control flow for templates, a new &lt;strong&gt;declarative&lt;/strong&gt; syntax of writing control flow in the template, thus providing the functionality of &lt;code&gt;*ngIf&lt;/code&gt; &lt;code&gt;*ngFor&lt;/code&gt;, and &lt;code&gt;*ngSwitch&lt;/code&gt; (directive-based control flow) into the framework itself.&lt;/p&gt;

&lt;p&gt;The template syntax has been debated for some time, with the Angular team and community providing their solutions, and after careful reasoning and their trust in the community, the &lt;code&gt;@-syntax&lt;/code&gt; (community proposal) was chosen to back the template control flow.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can read more about it (reason, benefits, implications … etc) in the &lt;a href="https://github.com/angular/angular/discussions/50719" rel="noopener noreferrer"&gt;Angular RFC: Built-in Control Flow&lt;/a&gt; and template syntax choice in the Angular &lt;a href="https://blog.angular.io/meet-angulars-new-control-flow-a02c6eee7843" rel="noopener noreferrer"&gt;blog post&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Loop control flow &lt;code&gt;@-for&lt;/code&gt;, is what grabbed my attention the most, because of the new supporting &lt;code&gt;@-empty&lt;/code&gt; block that shows a template when no items are in the list:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@for (product of products; track product.title) {
  &amp;lt;tr&amp;gt;
    &amp;lt;td&amp;gt;{{ product.title }}&amp;lt;/td&amp;gt;
    &amp;lt;td&amp;gt;{{ product.description }}&amp;lt;/td&amp;gt;
    &amp;lt;td&amp;gt;{{ product.price }}&amp;lt;/td&amp;gt;
    &amp;lt;td&amp;gt;{{ product.brand }}&amp;lt;/td&amp;gt;
    &amp;lt;td&amp;gt;{{ product.category }}&amp;lt;/td&amp;gt;
  &amp;lt;/tr&amp;gt;
} @empty {
  &amp;lt;p&amp;gt;No products added yet!&amp;lt;/p&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This new template syntax allows removing all the &lt;code&gt;ng-container&lt;/code&gt; and &lt;code&gt;ng-template&lt;/code&gt; elements on the template that supported &lt;code&gt;*ngIf&lt;/code&gt; and &lt;code&gt;*ngFor&lt;/code&gt; making templates more compact and offering a better user experience.&lt;/p&gt;

&lt;p&gt;In this article, I want to show how a &lt;em&gt;for&lt;/em&gt; loop code looks now in the template after using built-in control flow syntax, and a misconception I created for the &lt;code&gt;@-empty&lt;/code&gt; block when iterating over data loaded asynchronously (&lt;strong&gt;observable&lt;/strong&gt; results, or &lt;strong&gt;read-only&lt;/strong&gt; signal values from the &lt;strong&gt;toSignal&lt;/strong&gt; function). Let's dive into an example!&lt;/p&gt;

&lt;h2&gt;
  
  
  Hands-on! 🐱‍🏍
&lt;/h2&gt;

&lt;p&gt;This demo will have a &lt;code&gt;Products&lt;/code&gt; component that renders a list of products into a table. Below you see the iteration being done using the current &lt;code&gt;*ngFor&lt;/code&gt; structural directive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Component, inject } from '@angular/core';
import { AsyncPipe, CommonModule } from '@angular/common';
import { ProductService } from '../product.service';

@Component({
  selector: 'app-products',
  standalone: true,
  imports: [CommonModule, AsyncPipe],
  template: `
    &amp;lt;table&amp;gt;
      &amp;lt;thead&amp;gt;
        &amp;lt;tr&amp;gt;
          &amp;lt;th&amp;gt;Title&amp;lt;/th&amp;gt;
          &amp;lt;th&amp;gt;Description&amp;lt;/th&amp;gt;
          &amp;lt;th&amp;gt;Price&amp;lt;/th&amp;gt;
          &amp;lt;th&amp;gt;Brand&amp;lt;/th&amp;gt;
          &amp;lt;th&amp;gt;Category&amp;lt;/th&amp;gt;
        &amp;lt;/tr&amp;gt;
      &amp;lt;/thead&amp;gt;

      &amp;lt;tbody&amp;gt;
        &amp;lt;ng-container *ngIf="products$ | async as products"&amp;gt;
          &amp;lt;ng-container *ngIf="products.length; else noResults"&amp;gt;
            &amp;lt;tr *ngFor="let product of products"&amp;gt;
              &amp;lt;td&amp;gt;{{ product.title }}&amp;lt;/td&amp;gt;
              &amp;lt;td&amp;gt;{{ product.description }}&amp;lt;/td&amp;gt;
              &amp;lt;td&amp;gt;{{ product.price }}&amp;lt;/td&amp;gt;
              &amp;lt;td&amp;gt;{{ product.brand }}&amp;lt;/td&amp;gt;
              &amp;lt;td&amp;gt;{{ product.category }}&amp;lt;/td&amp;gt;
            &amp;lt;/tr&amp;gt;
          &amp;lt;/ng-container&amp;gt;

          &amp;lt;ng-template #noResults&amp;gt;
            &amp;lt;p&amp;gt;No results yet!&amp;lt;/p&amp;gt;
          &amp;lt;/ng-template&amp;gt;
        &amp;lt;/ng-container&amp;gt;
      &amp;lt;/tbody&amp;gt;
    &amp;lt;/table&amp;gt;
  `,
  styleUrls: ['./products.component.scss'],
})
export class ProductsComponent {
  products$ = inject(ProductService).getProducts(); 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see the &lt;code&gt;ng-template | ng-container&lt;/code&gt; elements used, we first check for a &lt;strong&gt;null&lt;/strong&gt; case, guarding against the initial &lt;strong&gt;null&lt;/strong&gt; value emitted from the async pipe, making sure we get the result from the products observable when emitted, and then check if the list is empty to render the default message or render the products in the table.&lt;/p&gt;

&lt;p&gt;Now you correctly ask, what would it look like with the new &lt;code&gt;@-for&lt;/code&gt; control flow 🤔?&lt;/p&gt;

&lt;p&gt;Look at this code 😍:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...

@Component({
  ...
  template: `
    &amp;lt;table&amp;gt;
      ...

      &amp;lt;tbody&amp;gt;
        @if (products$ | async; as products) {
          @for (product of products; track product.title) {
           &amp;lt;tr&amp;gt;
             &amp;lt;td&amp;gt;{{ product.title }}&amp;lt;/td&amp;gt;
             &amp;lt;td&amp;gt;{{ product.description }}&amp;lt;/td&amp;gt;
             &amp;lt;td&amp;gt;{{ product.price }}&amp;lt;/td&amp;gt;
             &amp;lt;td&amp;gt;{{ product.brand }}&amp;lt;/td&amp;gt;
             &amp;lt;td&amp;gt;{{ product.category }}&amp;lt;/td&amp;gt;
           &amp;lt;/tr&amp;gt;
          } @empty {
           &amp;lt;p&amp;gt;No results yet!&amp;lt;/p&amp;gt;
          }
        }
      &amp;lt;/tbody&amp;gt;
    &amp;lt;/table&amp;gt;
  `,
  ...,
})
export class ProductsComponent {
  products$ = inject(ProductService).getProducts(); 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;code&gt;ng-container | ng-template&lt;/code&gt; elements are present. It is the new &lt;code&gt;@-for&lt;/code&gt; and &lt;code&gt;@-empty&lt;/code&gt; in combination that removes the need to check if the products list is empty and what template to render based on that, default message or products table hence no more "&lt;strong&gt;imperative&lt;/strong&gt;" check.&lt;/p&gt;

&lt;p&gt;And it's the &lt;code&gt;@-if&lt;/code&gt; block that does the check for the &lt;strong&gt;null&lt;/strong&gt; value emitted from the async pipe. Also, the new syntax enforces the use of &lt;code&gt;track&lt;/code&gt;, a function that improves performance. Thus we have less, cleaner code, more performant, and easy to understand, read, and write.&lt;/p&gt;

&lt;h3&gt;
  
  
  My misconception for @-empty block 😁
&lt;/h3&gt;

&lt;p&gt;When I first started experimenting with the new Control Flow, I was expecting the &lt;code&gt;@-empty&lt;/code&gt; block in combination with &lt;code&gt;@-for&lt;/code&gt; block to be working under the hood like &lt;strong&gt;for await of&lt;/strong&gt; statement in JavaScript -  in the sense that if the data to be iterated loads asynchronously as the result of an observable or a read-only signal created by toSignal function, it would wait until the data is loaded and then decide if the &lt;code&gt;@-empty&lt;/code&gt; block renders or not.&lt;/p&gt;

&lt;p&gt;In short, I thought we did not need to check for a &lt;strong&gt;null&lt;/strong&gt; value when waiting for an observable to emit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...

@Component({
  ...
  template: `
    &amp;lt;table&amp;gt;
      ...
      &amp;lt;tbody&amp;gt;
        // no @if check here...
        @for (product of products$ | async; track product.title) {
          &amp;lt;tr&amp;gt;
            &amp;lt;td&amp;gt;{{ product.title }}&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;{{ product.description }}&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;{{ product.price }}&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;{{ product.brand }}&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;{{ product.category }}&amp;lt;/td&amp;gt;
          &amp;lt;/tr&amp;gt;
        } @empty {
          &amp;lt;p&amp;gt;No results yet!&amp;lt;/p&amp;gt;
        }
      &amp;lt;/tbody&amp;gt;
    &amp;lt;/table&amp;gt;
  `,
  ...,
})
export class ProductsComponent {
  products$ = inject(ProductService).getProducts(); 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or when reading from a read-only signal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...

@Component({
  ...
  template: `
    &amp;lt;table&amp;gt;
      ...
      &amp;lt;tbody&amp;gt;
        // no @if check here...
        @for (product of products(); track product.title) {
          &amp;lt;tr&amp;gt;
            &amp;lt;td&amp;gt;{{ product.title }}&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;{{ product.description }}&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;{{ product.price }}&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;{{ product.brand }}&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;{{ product.category }}&amp;lt;/td&amp;gt;
          &amp;lt;/tr&amp;gt;
        } @empty {
          &amp;lt;p&amp;gt;No results yet!&amp;lt;/p&amp;gt;
        }
      &amp;lt;/tbody&amp;gt;
    &amp;lt;/table&amp;gt;
  `,
  ...,
})
export class ProductsComponent {
  products = toSignal(this.productService.getProducts(), { initialValue: null });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But just like the if/else statement of any programming language that works on a sync sequence of values, the same stands for the &lt;code&gt;@-for&lt;/code&gt; control flow in templates.&lt;/p&gt;

&lt;p&gt;What happens in this case, is that first the &lt;code&gt;@-empty&lt;/code&gt; block with the "No results yet!" message is rendered, and then after the data comes from the server, the products table is rendered:&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%2F3azmp9gfk8kj5mxz3vtq.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%2F3azmp9gfk8kj5mxz3vtq.gif" alt="Demo how it works with no @if check first" width="778" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;During the time RFC was open for review, I left a &lt;strong&gt;&lt;a href="https://github.com/angular/angular/discussions/50719" rel="noopener noreferrer"&gt;comment&lt;/a&gt;&lt;/strong&gt; asking if an optional condition could be added to the &lt;code&gt;@-empty&lt;/code&gt; block ({: empty} at the time of comment was left) to make it able to wait until data is loaded. The Angular team cares about its community and takes into consideration their input, and it may do something for this behavior in the near future.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;FYI&lt;/strong&gt;: Angular v17 is officially in a &lt;a href="https://github.com/angular/angular/releases/tag/17.0.0-rc.0" rel="noopener noreferrer"&gt;release candidate&lt;/a&gt; phase now. Feel free to grab and experience its new features.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Special thanks to &lt;a class="mentioned-user" href="https://dev.to/kreuzerk"&gt;@kreuzerk&lt;/a&gt; , &lt;a class="mentioned-user" href="https://dev.to/danielglejzner"&gt;@danielglejzner&lt;/a&gt; and &lt;a href="https://twitter.com/eugeniyoz" rel="noopener noreferrer"&gt;@eugenioz&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;I hope you enjoyed it 🙌. If you liked the article please feel free to share it with your friends and colleagues.&lt;/p&gt;

&lt;p&gt;For any questions or suggestions, feel free to comment below 👇.&lt;/p&gt;

&lt;p&gt;If this article is interesting and useful to you, and you don't want to miss future articles, follow me at &lt;a href="https://twitter.com/lilbeqiri" rel="noopener noreferrer"&gt;@lilbeqiri&lt;/a&gt;, &lt;a href="https://dev.to/ilirbeqirii"&gt;dev.to&lt;/a&gt;, or &lt;a href="https://lilbeqiri.medium.com/" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;. 📖&lt;/p&gt;

</description>
      <category>angular</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Should You Pair Signals &amp; OnPush?</title>
      <dc:creator>Ilir Beqiri</dc:creator>
      <pubDate>Thu, 21 Sep 2023 16:56:09 +0000</pubDate>
      <link>https://dev.to/playfulprogramming-angular/should-you-pair-signals-onpush-1jko</link>
      <guid>https://dev.to/playfulprogramming-angular/should-you-pair-signals-onpush-1jko</guid>
      <description>&lt;p&gt;When building a web application, there are different aspects that we take into consideration, &lt;strong&gt;performance&lt;/strong&gt; being one of them. Especially when working on a considerable Angular codebase, there is always space for performance improvements.&lt;/p&gt;

&lt;p&gt;An inherited codebase is what I have been working on recently, and the main thing to be improved was the performance of the application — refactoring to libraries, smart and dumb components, and starting to utilize the &lt;code&gt;OnPush&lt;/code&gt; change detection strategy amongst other improvements.&lt;/p&gt;

&lt;p&gt;In this article, I want to share the issue we faced while sparingly adding the &lt;code&gt;OnPush&lt;/code&gt; strategy to components. Additionally, I will elaborate on a few solutions that are already known that we can use, the latest one being the future, new reactive primitive, Angular Signals.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The OnPush Change Detection&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Change Detection is the mechanism that makes sure that the application state is in sync with the UI. At a high level, Angular walks your components from top to bottom, looking for changes. The way it does, this is by comparing each current value of expressions in the template with the previous values they had using the &lt;strong&gt;strict equality comparison operator&lt;/strong&gt; (&lt;strong&gt;===&lt;/strong&gt;). This is known as &lt;strong&gt;dirty checking&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;You can read more about in the &lt;a href="https://angular.io/guide/change-detection-skipping-subtrees" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even though change detection is optimized and performant, in applications with large component trees, running change detection across the whole app too frequently may cause &lt;strong&gt;slowdowns&lt;/strong&gt; and &lt;strong&gt;performance&lt;/strong&gt; issues. This can be addressed by using the &lt;code&gt;OnPush&lt;/code&gt; change detection strategy, which tells Angular to never run the change detection for a component unless:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;At the time the &lt;strong&gt;component is created.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;strong&gt;component is dirty.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;There are actually 3 criteria when OnPush CD runs, and you can find more about them in this &lt;a href="https://blog.simplified.courses/angular-change-detection-onpush-or-not/" rel="noopener noreferrer"&gt;article&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This allows to skip change detection in an entire component subtree.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Problem:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To better understand the issue, below is a small reproduction of the app supporting our case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  selector: 'my-app',
  standalone: true,
  imports: [CommonModule, RouterLink, RouterOutlet],
  template: `
    &amp;lt;h1&amp;gt;OnPush &amp;amp; Signals&amp;lt;/h1&amp;gt;
    &amp;lt;a routerLink="/"&amp;gt;Home&amp;lt;/a&amp;gt; &amp;amp;nbsp;
    &amp;lt;a routerLink="/products"&amp;gt;Products &amp;lt;/a&amp;gt;
    &amp;lt;hr &amp;gt;

    &amp;lt;router-outlet&amp;gt;&amp;lt;/router-outlet&amp;gt;
  `,
})
export class AppComponent {
  name = 'OnPush &amp;amp; Signals';
}

bootstrapApplication(App, {
  providers: [
    provideHttpClient(),
    provideRouter([
      {
        path: '',
        component: HomeComponent,
      },
      {
        path: 'products',
        loadComponent: () =&amp;gt;
          import('./products-shell/products-shell.component'),
        children: [
          {
            path: '',
            loadChildren: () =&amp;gt; import('./products').then((r) =&amp;gt; r.routes),
          },
        ],
      },
    ]),
  ],
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using new standalone APIs in Angular, an application is bootstrapped with &lt;strong&gt;HttpClient&lt;/strong&gt; and &lt;strong&gt;Router&lt;/strong&gt; configured. The application has 2 routes configured, the default one for &lt;strong&gt;HomeComponent&lt;/strong&gt;, and the 'products' for the &lt;strong&gt;Product&lt;/strong&gt; feature (in our case being an Nx library) which is lazily-loaded when the route is activated and rendered in the lazily-loaded &lt;strong&gt;ProductShell&lt;/strong&gt; component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  selector: 'app-products-shell',
  standalone: true,
  imports: [RouterOutlet],
  changeDetection: ChangeDetectionStrategy.OnPush, // configure OnPush
  template: `
    &amp;lt;header&amp;gt;
      &amp;lt;h2&amp;gt;Products List&amp;lt;/h2&amp;gt;
    &amp;lt;/header&amp;gt;

    &amp;lt;router-outlet&amp;gt;&amp;lt;/router-outlet&amp;gt;
  `,
  styleUrls: ['./products-shell.component.css'],
})
export default class ProductsShellComponent { }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;Product&lt;/strong&gt; feature itself has the following route configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const routes: Routes = [
  {
    path: '',
    loadComponent: () =&amp;gt; import('./products.component'),
    children: [
      {
        path: 'list',
        loadComponent: () =&amp;gt; import('./products-list/products-list.component'),
      },
      {
        path: '',
        redirectTo: 'list',
        pathMatch: 'full',
      },
    ],
  },
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s first have a look at the way it should not be done, and then check the solutions:&lt;/p&gt;

&lt;h2&gt;
  
  
  Illustrating the problem
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;ProductList&lt;/strong&gt; component below calls the &lt;code&gt;getProducts&lt;/code&gt; function inside the &lt;code&gt;ngOnInit&lt;/code&gt; hook to get the list of products and then render it into a table.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  selector: 'app-products-list',
  standalone: true,
  imports: [NgFor],
  template: `
    &amp;lt;table&amp;gt;
      &amp;lt;thead&amp;gt;
        &amp;lt;tr&amp;gt;
          &amp;lt;th&amp;gt;Title&amp;lt;/th&amp;gt;
          &amp;lt;th&amp;gt;Description&amp;lt;/th&amp;gt;
          &amp;lt;th&amp;gt;Price&amp;lt;/th&amp;gt;
          &amp;lt;th&amp;gt;Brand&amp;lt;/th&amp;gt;
          &amp;lt;th&amp;gt;Category&amp;lt;/th&amp;gt;
        &amp;lt;/tr&amp;gt;
      &amp;lt;/thead&amp;gt;

      &amp;lt;tbody&amp;gt;
        &amp;lt;tr *ngFor="let product of products"&amp;gt;
          &amp;lt;td&amp;gt;{{ product.title }}&amp;lt;/td&amp;gt;
          &amp;lt;td&amp;gt;{{ product.description }}&amp;lt;/td&amp;gt;
          &amp;lt;td&amp;gt;{{ product.price }}&amp;lt;/td&amp;gt;
          &amp;lt;td&amp;gt;{{ product.brand }}&amp;lt;/td&amp;gt;
          &amp;lt;td&amp;gt;{{ product.category }}&amp;lt;/td&amp;gt;
        &amp;lt;/tr&amp;gt;
      &amp;lt;/tbody&amp;gt;
    &amp;lt;/table&amp;gt;
  `,
  styleUrls: ['./products-list.component.css'],
})
export default class ProductsListComponent implements OnInit {
  products: Product[] =[];
  productService = inject(ProductsService);

  ngOnInit() {
    this.productService.getProducts().subscribe((products) =&amp;gt; {
      this.products = products;
    });
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will be rendered inside the &lt;strong&gt;Products&lt;/strong&gt; component which wraps the &lt;code&gt;&amp;lt;router-outlet&amp;gt;&lt;/code&gt; inside a &lt;code&gt;div&lt;/code&gt; for page spacing purposes (in our case):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  selector: 'app-products',
  standalone: true,
  imports: [RouterOutlet],
  template: `
   &amp;lt;div class="main-content"&amp;gt;
    &amp;lt;router-outlet&amp;gt;&amp;lt;/router-outlet&amp;gt;
   &amp;lt;/div&amp;gt;
  `,
  styles: [`.main-content { margin-top: 15px }`],
})
export default class ProductsComponent {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first sight, this code seems correct, but no products will be rendered on the table, and no errors in the console.&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%2Ffckx9owst5iflq9jys50.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%2Ffckx9owst5iflq9jys50.gif" alt="Navigating from home page to the product list page when no data is rendered because of the change detection issue" width="600" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What could be happening? 🤯&lt;/p&gt;

&lt;p&gt;This happens because of &lt;strong&gt;ProductShell&lt;/strong&gt; (root) component is being configured using OnPushchange detection, and the "imperative way" of retrieving the products list. The products list is retrieved successfully, and the data model is changed, marking the &lt;strong&gt;ProductsList&lt;/strong&gt; component as dirty, but not its ancestor components. Marking &lt;strong&gt;ProductShell&lt;/strong&gt;  &lt;code&gt;OnPush&lt;/code&gt; skips all subtree of components from being checked for change unless it is marked dirty, hence data model change is not reflected on UI.&lt;br&gt;
Now that we understand what the issue is, there are a few ways that can solve it. Of course, the easiest one is just reverting to the &lt;strong&gt;Default&lt;/strong&gt; change detection and everything works. But let's see what are the other solutions out there:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution 1: Declarative Pattern with AsyncPipe&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of imperatively subscribing to the &lt;code&gt;getProducts&lt;/code&gt; function in the component, we subscribe to it in the template by using the &lt;code&gt;async&lt;/code&gt; pipe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  ...
  template: `
    &amp;lt;table&amp;gt;
      ...
      &amp;lt;tbody&amp;gt;
        &amp;lt;tr *ngFor="let product of products$ | async"&amp;gt;
          &amp;lt;td&amp;gt;{{ product.title }}&amp;lt;/td&amp;gt;
          &amp;lt;td&amp;gt;{{ product.description }}&amp;lt;/td&amp;gt;
          &amp;lt;td&amp;gt;{{ product.price }}&amp;lt;/td&amp;gt;
          &amp;lt;td&amp;gt;{{ product.brand }}&amp;lt;/td&amp;gt;
          &amp;lt;td&amp;gt;{{ product.category }}&amp;lt;/td&amp;gt;
        &amp;lt;/tr&amp;gt;
      &amp;lt;/tbody&amp;gt;
    &amp;lt;/table&amp;gt;
  `
})
export default class ProductsListComponent {
  productService = inject(ProductsService);
  products$ = this.productService.getProducts();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;async&lt;/code&gt; pipe automatically subscribes to the observable returned by the &lt;code&gt;getProducts&lt;/code&gt; function and returns the latest value it has emitted. When a new value is emitted, it marks the component to be checked for changes, including ancestor components (&lt;strong&gt;ProductShell&lt;/strong&gt; is one of them in this case). Now, Angular will check for changes &lt;strong&gt;ProductShell&lt;/strong&gt; component together with its component tree including the &lt;strong&gt;ProductList&lt;/strong&gt; component, and thus UI will be updated with products rendered on a table:&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%2Fzxstqks4cj67pbx92nmj.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%2Fzxstqks4cj67pbx92nmj.gif" alt="Navigating from home page to the product's list page, we get the list of products rendered on the table." width="600" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution 2: Using Angular Signals 🚦&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Signals&lt;/code&gt;, introduced in Angular v16 in the developer preview, represent a new reactivity model that tells the Angular about which data the UI cares about, and when that data changes thus easily keeping UI and data changes in sync. Together with the future &lt;a href="https://github.com/angular/angular/discussions/49682" rel="noopener noreferrer"&gt;&lt;strong&gt;Signal-Based&lt;/strong&gt;&lt;/a&gt; components, will make possible fine-grained reactivity and change detection in Angular.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;You can read more about &lt;code&gt;Signals&lt;/code&gt; in the &lt;a href="https://angular.io/guide/signals" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In its basics, a &lt;code&gt;signal&lt;/code&gt; is a wrapper around a value that can notify interested consumers when that value changes. In this case, the ‘&lt;em&gt;products&lt;/em&gt;’ data model will be a signal of the products which will be bound directly to the template and thus be tracked by Angular as that component’s dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  ...
  template: `
    &amp;lt;table&amp;gt;
      ...
      &amp;lt;tbody&amp;gt; &amp;lt;!-- getter function: read the signal value--&amp;gt;
        &amp;lt;tr *ngFor="let product of products()"&amp;gt;
          &amp;lt;td&amp;gt;{{ product.title }}&amp;lt;/td&amp;gt;
          &amp;lt;td&amp;gt;{{ product.description }}&amp;lt;/td&amp;gt;
          &amp;lt;td&amp;gt;{{ product.price }}&amp;lt;/td&amp;gt;
          &amp;lt;td&amp;gt;{{ product.brand }}&amp;lt;/td&amp;gt;
          &amp;lt;td&amp;gt;{{ product.category }}&amp;lt;/td&amp;gt;
        &amp;lt;/tr&amp;gt;
      &amp;lt;/tbody&amp;gt;
    &amp;lt;/table&amp;gt;
  `
})
export default class ProductsListComponent implements OnInit {
  products = signal&amp;lt;Product[]&amp;gt;([]);
  productService = inject(ProductsService);

  ngOnInit() {
    this.productService.getProducts().subscribe((products) =&amp;gt; {
      this.products.set(products);
    });
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the '&lt;em&gt;products&lt;/em&gt;' signal gets a new value (through the setter function), being read directly on the template (through a getter function), Angular detects changed bindings, marking the &lt;strong&gt;ProductList&lt;/strong&gt; component and all its ancestors' components as dirty / for change on the next change detection cycle.&lt;/p&gt;

&lt;p&gt;Then, Angular will check for changes &lt;strong&gt;ProductShell&lt;/strong&gt; component together with its component tree including the &lt;strong&gt;ProductList&lt;/strong&gt; component, and thus UI will be updated with products rendered on a table:&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%2Fs9ruu37c8xvn58do0x9l.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%2Fs9ruu37c8xvn58do0x9l.gif" alt="Navigating from the home page to the product's list page, we get the list of products rendered on the table." width="600" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same solution can be achieved by following a declarative approach using the &lt;code&gt;toSignal&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  selector: 'app-products-list',
  standalone: true,
  imports: [NgFor, AsyncPipe],
  template: `
    &amp;lt;table&amp;gt;
      …
        &amp;lt;tr *ngFor="let product of products()"&amp;gt;
          &amp;lt;td&amp;gt;{{ product.title }}&amp;lt;/td&amp;gt;
          &amp;lt;td&amp;gt;{{ product.description }}&amp;lt;/td&amp;gt;
          &amp;lt;td&amp;gt;{{ product.price }}&amp;lt;/td&amp;gt;
          &amp;lt;td&amp;gt;{{ product.brand }}&amp;lt;/td&amp;gt;
          &amp;lt;td&amp;gt;{{ product.category }}&amp;lt;/td&amp;gt;
        &amp;lt;/tr&amp;gt;
      …
    &amp;lt;/table&amp;gt;
  `
})
export default class ProductsListComponent implements OnInit {
  productService = inject(ProductsService);
  products: Signal&amp;lt;Product[]&amp;gt; = toSignal(this.productService.getProducts(), {
    initialValue: [],
  });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;toSignal&lt;/code&gt; is a utility function provided by &lt;a href="https://angular.io/api/core/rxjs-interop" rel="noopener noreferrer"&gt;@angular/core.rxjs-interop&lt;/a&gt; (in developer preview) package to integrate signals with RxJs observables. It creates a signal which tracks the value of an Observable. It behaves similarly to the &lt;a href="https://angular.io/api/common/AsyncPipe" rel="noopener noreferrer"&gt;&lt;code&gt;async&lt;/code&gt;&lt;/a&gt; pipe in templates, it marks the &lt;strong&gt;ProductList&lt;/strong&gt; component and all its ancestors for change / dirty thus UI will be updated accordingly.&lt;/p&gt;

&lt;p&gt;You can find and play with the final code here: &lt;a href="https://stackblitz.com/edit/onpush-cd-deep-route?file=src/main.ts" rel="noopener noreferrer"&gt;https://stackblitz.com/edit/onpush-cd-deep-route?file=src/main.ts&lt;/a&gt; 🎮&lt;/p&gt;

&lt;p&gt;Special thanks to &lt;a class="mentioned-user" href="https://dev.to/kreuzerk"&gt;@kreuzerk&lt;/a&gt;,  &lt;a class="mentioned-user" href="https://dev.to/eneajaho"&gt;@eneajaho&lt;/a&gt;, and &lt;a class="mentioned-user" href="https://dev.to/danielglejzner"&gt;@danielglejzner&lt;/a&gt;  for review.&lt;/p&gt;

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

&lt;p&gt;This is my first article, and I hope you enjoyed it 🙌.&lt;/p&gt;

&lt;p&gt;For any questions or suggestions, feel free to leave a comment below 👇.&lt;/p&gt;

&lt;p&gt;If this article is interesting and useful to you, and don’t want to miss future articles, give me a follow at &lt;a href="https://twitter.com/lilbeqiri" rel="noopener noreferrer"&gt;@lilbeqiri&lt;/a&gt;, &lt;a href="http://lilbeqiri.medium.com" rel="noopener noreferrer"&gt;Medium&lt;/a&gt; or &lt;a href="https://dev.to/ilirbeqirii"&gt;dev.to&lt;/a&gt;. 📖&lt;/p&gt;

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