Using a new way to create templates – control flow – The Angular Renaissance

Since version 2 of the framework, the HTML template syntax has remained relatively stable and without much evolution. By using custom properties, we can evaluate conditions and iterate over lists and other forms of flow control to create visualization logic in components. The *ngIf, *ngFor, and *ngSwitch directives are used to improve the developer experience, internally generating the elements in the HTML. You can read more about this in Chapter 4, Components and Pages.

Starting with version 17, the Angular team introduced a new form of control flow in HTML. The syntax in this version is in developer preview, which means that it is stable for production but may have changes in future versions. Let’s refactor our code to use the syntax and see the difference in practice.

In the app.component.html file, we will change the following:
@if (loadService.isLoading) {
  <app-loading-overlay />
}
<router-outlet></router-outlet>

Here, we can notice the first new structure of the new control flow, if. Using the command in the HTML template with the @ symbol, we apply the conditional statement as in TypeScript, evaluating whether the function or variable is true or false.

The novelty of the syntax is that we now have the @else instruction facilitating the chaining of conditionals, without the need to use the ng-template directive for this purpose.

We will refactor the list-entries.component.html file as follows:
<section class=”mb-8″>
  <h2 class=”mb-4 text-xl font-bold”>List of entries</h2>
  <ul class=”rounded border shadow”>
    @for (item of exerciseList; track item.id) {
    <li>
      <app-entry-item
        [exercise-set]=”item”
        (deleteEvent)=”deleteEvent.emit($event)”
        (editEvent)=”editEvent.emit($event)”
      />
    </li>
    } @empty {
      <div>
        No Items!
      </div>
    }
  </ul>
</section>

In this example, we are using the @for instruction to replace the *ngFor directive. We provide the name of the variable that will receive the list iteration, in this case, item, and the list itself, in this component, named exerciseList.

In Chapter 4, Components and Pages, we learned the good practice of using the trackBy property of the *ngFor directive to improve list rendering performance. This good practice is now mandatory in the new @for syntax, and in this case, it is even simpler as we can simply pass the attribute that Angular should check.

A new element is the @empty instruction, which indicates what should be shown if the list in question is empty.

The new @for instruction, in addition to improving the development experience, is also 90% faster, according to the Angular team, when rendering lists than the previous solution. That’s because control statements aren’t just sugar syntax for directives; the template engine has been redesigned and the instructions manipulate Angular’s internal DOM rendering elements.

Finally, let’s refactor the new-entry-form-reactive.component.html file as follows:
@if (entryForm.get(‘date’)?.invalid && entryForm.get(‘date’)?.touched) {
    <div class=”mt-1 text-red-500″>Date is required.</div>
    }
@if (showSuggestions) {
    <ul
      class=”absolute z-10 mt-2 w-auto rounded border border-gray-300 bg-white”
    >
      @for (suggestion of exercises$ | async; track suggestion.id) {
      <li
        class=”cursor-pointer px-3 py-2 hover:bg-blue-500 hover:text-white”
        (click)=”selectExercise(suggestion.description)”
      >
        {{ suggestion.description }}
      </li>
      }
    </ul>
    } @if (entryForm.get(‘exercise’)?.invalid &&
    entryForm.get(‘exercise’)?.touched) {
    <div class=”mt-1 text-red-500″>Exercise is required.</div>
    }
@if (entryForm.get(‘reps’)?.invalid && entryForm.get(‘reps’)?.touched) {
    <div class=”mt-1 text-red-500″>
      Reps is required and must be a positive number.
    </div>
    }@else if ( entryForm.get(‘reps’)?.errors?.[‘isNotMultiple’] &&
    entryForm.get(‘reps’)?.touched) {
    <div class=”mt-1 text-red-500″>
      Reps is required and must be multiple of 3.
    </div>
    }

In this file, we are replacing the conditionals that evaluate form errors with the @if statement. For the @for instruction that we use to render the list of exercises, we can notice that the use of the async pipe remains very similar to the *ngFor directive, and we added track to further improve the rendering of the list. Finally, we are using the @else if command to chain two conditionals.

We can note that we do not need to perform any additional configuration to use the flow control syntax because this functionality is fully compatible with the previous mechanics and they can coexist in the same project and even in the same file.

The Angular team even created a migration command in the Angular CLI, as follows:
ng g @angular/core:control-flow

In the next section, we will see a new possibility that this template refactoring provides to our application, the option of lazy loading components in our HTML templates.

No Responses

Leave a Reply

Your email address will not be published. Required fields are marked *



Terms of Use | About yeagerback | Privacy Policy | Cookies | Accessibility Help | Contact yeagerback