is a variable in a template good or bad?

The recent announcement of the @let block in Angular has sparked a lot of discussion in the developer community, with some seeing it as a valuable addition and others seeing it as unnecessary complexity.

Benefits of using

Proponents argue that @let simplifies template logic by allowing variables to be declared within a template, avoiding problems with false values ​​and improving readability. This allows for more linear and cleaner code, especially when dealing with complex conditions and asynchronous data.

Consider the problem with falsy values: Previously, to declare a variable in an Angular template, developers often used the ngIf directive with the as keyword. This approach has a limitation: falsy values ​​such as 0, empty strings (“”), null, undefined, and false prevented the content from being displayed.

For example:

<div *ngIf="userName$ | async as userName">
  <h1>Welcome, {{ userName }}</h1>
</div>

If userName was an empty string, nothing would be displayed. The @let block solves this problem:

<div>
  @let userName = (userName$ | async) ?? 'Guest';
  <h1>Welcome, {{ userName }}</h1>
</div>

Let's look at another good example of using this feature in a template where we are working with tables with dynamic columns, where the column definition and value are derived from complex configurations. Anyone who has worked on an application with large tables knows the problems that come with it. The @let block can make working with tables much easier.

Using the @let block:

<table mat-table [dataSource]="dataSource">
  @for (columnDef of columnDefs) {
    @let property = columnDef.propertyName;
    <ng-container [matColumnDef]="columnDef.name">
      <th mat-header-cell *matHeaderCellDef>{{ columnDef.header }}</th>
      <td mat-cell *matCellDef="let element">
        @let cellValue = element[property];
        <ng-container *ngIf="columnDef.cellType === 'link'; else plainCell">
          <a [routerLink]="cellValue?.routerLink">{{ cellValue?.value }}</a>
        </ng-container>
        <ng-template #plainCell>{{ cellValue }}</ng-template>
      </td>
    </ng-container>
  }
</table>

The usual way:

<table mat-table [dataSource]="dataSource">
  <ng-container *ngFor="let columnDef of columnDefs">
    <ng-container [matColumnDef]="columnDef.name">
      <th mat-header-cell *matHeaderCellDef>{{ columnDef.header }}</th>
      <td mat-cell *matCellDef="let element">
        <ng-container *ngIf="columnDef.cellType === 'link'; else plainCell">
          <a [routerLink]="element[columnDef.propertyName]?.routerLink">{{ element[columnDef.propertyName]?.value }}</a>
        </ng-container>
        <ng-template #plainCell>{{ element[columnDef.propertyName] }}</ng-template>
      </td>
    </ng-container>
  </ng-container>
</table>

Arguments against:

Critics argue that the @let block introduces unnecessary complexity and can lead to confusion. Here are some opinions and an example:

  • Increased cognitive load: The introduction of @let adds another concept for developers to learn and understand. This can increase cognitive load, especially for new developers who are already trying to master Angular's vast capabilities.

  • Potential for Misuse: There is a risk that developers will overuse or misuse @let, resulting in templates that are harder to read and maintain. For example, nesting multiple @let blocks in complex templates can make code less understandable. Extra care will be needed during code reviews to ensure that unnecessary template variables are not created.

  • Existing solutions are sufficient: Critics believe that Angular's existing features, especially the ability to convert observables into signals, are sufficient to handle most use cases. They argue that the introduction of @let does not provide significant advantages over these existing solutions.

Example:

<div>
  @let firstName = user?.firstName;
  @let lastName = user?.lastName;
  @let fullName = `${firstName} ${lastName}`;
  <p>{{ fullName }}</p>
  @if (user?.address) {
    @let street = user.address.street;
    @let city = user.address.city;
    <p>{{ street }}, {{ city }}</p>
  }
</div>

This example demonstrates the potential convenience of @let, but also shows how multiple @let declarations can lead to confusion in a template.

How do you rate the usability of @let compared to other approaches to working in Angular templates?

Similar Posts

Leave a Reply

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