Angular Control Flow: полное руководство

В этой статье мы углубимся в новый поток управления, который был добавлен в 17 версии и который заставит вас забыть о таких директивах, как ngIf, ngSwitch и ngFor, благодаря новому синтаксису для написания операторов if , if/else и switch , а также цикла for в нашем шаблоне.

@if условие

Чтобы отобразить блок шаблона на основе условия, всегда использовалась директива ngIf :

@Component({
  standalone: true,
  template: `<div *ngIf="condition"> ... </div>`,
  imports: [NgIf]
})
export class MyComponent {}

У этой простой директивы действительно есть некоторые минусы :

  • Синтаксис неинтуитивен и очень связан с инфраструктурой;
  • Невозможно применить его к группам элементов, для этого вам нужно обернуть элементы внутри контейнера или ng-template / ng-container ;
  • Вам необходимо импортировать CommonModule  или директиву NgIf в ваши модули.

Новое условие @if позволяет получить тот же результат:

@if (condition) {
  * your content *
}Язык кода:  HTML, XML  ( xml )

@if предлагает вам более чистый синтаксис, условные блоки сразу выделяются при чтении шаблона, что позволяет вам заключать группы элементов в фигурные скобки и, самое главное: больше не нужно импортировать модули или директивы .

@else и @else/if

условие if/else всегда было проблемой в Angular:

<div *ngIf="condition; else otherTemplate">
  * your content *
</div>

<ng-template #otherTemplate>
  * your other content *
</ng-template>

Потребность в ng-шаблоне в сочетании с переменной шаблона для предоставления в директиве ngIf резервного блока всегда была сложной и не очень немедленной.

И вот здесь @if помогает больше всего: его можно расширить с помощью @else :

@if (condition) {
  * your content *
} @else {
  * your other content *
}

Но дело не только в этом: @if можно еще больше расширить с помощью @else/if :

@if (condition) {
  * your content *
} @else if (secondCondition) {
  * your second content *
} @else {
  * your other content *
}

Благодаря этому вы можете создавать шаблоны со сложными условиями, написав чистый и интуитивно понятный код. Легко читается, прост в обслуживании.

Теперь давайте продолжим с @switch .

@switch условие

До сегодняшнего дня директива ngSwitch использовалась для отображения определенного блока шаблона в списке на основе условия переключения:

<div [ngSwitch]="condition">
  <div *ngSwitchCase="value1">* content block value1 *</div>
  <div *ngSwitchCase="value2">* content block value2 *</div>
  <div *ngSwitchDefault>* default content *</div>
</div>

Аналогично @if, теперь есть совершенно новое условие @switch :

@switch(condition) {
  @case ('value1') {
    * content block value1 *
  } @case ('value2') {
    * content block value2 *
  } @default {
    * default content *
  }
}

В этом случае вы можете получить более чистый синтаксис и отказаться от импорта .

Вот мы и подошли к последней теме: цикл @for .

@for цикл

Отображение списка блоков в шаблоне для представления списка элементов является ключевой концепцией многих фреймворков, и в Angular эту задачу можно выполнить с помощью директивы ngFor :

<ul>
  <li *ngFor="let item of itemList">
    {{ item.name }}
  </li>
</ul>

Эта директива позволяет вам создать индивидуальный блок для каждого элемента списка благодаря возможности использовать информацию об одном элементе и некоторых локальных переменных, предоставляемых самой директивой:

  • index: number: индекс элемента в списке;
  • count: number: длина списка;
  • first: boolean: true, если элемент является первым в списке;
  • last: boolean: true, если элемент является последним в списке;
  • even: boolean: true, если индекс элемента четный;
  • odd: boolean: true, если индекс элемента нечетный.

Кроме того, директива ngFor принимает функцию trackBy в качестве необязательного параметра, используемого для предоставления Angular уникального идентификатора для каждого элемента списка (например, идентификатора):

<ul>
  <li *ngFor="let item of itemList; trackBy: itemById">
    {{ item.name }}
  </li>
</ul>Язык кода:  HTML, XML  ( xml )
 itemById(index, item) {
  return item.id;
}

Благодаря этому Angular может оптимизировать производительность при замене списка или изменении элемента.

Итак, чтобы заменить директиву ngFor, новый поток управления предоставляет @for :

<ul>
  @for (item of itemList; track item.id; let idx = $index, e = $even) {
    <li>{{ item.name }}</li>
  }
</ul>

Этот новый синтаксис вносит некоторые важные изменения:

  • Улучшение производительности до 90% по сравнению с ngFor благодаря новому алгоритму, используемому для реализации @for ;
  • Функция trackBy заменяется свойством track , которое требует предоставления выражения, которое легче писать и читать, чем целую функцию;
  • Свойство track необходимо , чтобы мы не забыли его, как это обычно происходит с функцией trackBy;
  • Локальные переменные теперь имеют префикс $ (например: $index ).

Кроме того, вы также можете получить более чистый синтаксис и отказаться от импорта .

@empty блок

Мы можем добавить @empty блок под @for блоком. Содержимое @empty блока отображается, если коллекция, которую мы передали в @for блок, пуста:

<ul>
@for (item of emptyCollection; track item.id;) {
<li><strong>{{item.name}}</strong></li>
}
@empty {
  <span>The collection is empty</span>
}
</ul>

Заключение

Как вы можете видеть, новый поток управления предлагает новый способ написания сложных шаблонных условий в наших приложениях Angular, что обеспечивает повышение производительности и более удобный в обслуживании код.