Как использовать ngIf и ngFor?
ngIf и ngFor — это структурные директивы в Angular, которые управляют отображением DOM-элементов на основе условий (ngIf) или итерации по массиву (ngFor). Они предшествуют элементу DOM и начинаются с символа *, что означает «структурную» директиву — такую, которая может изменять структуру DOM (например, добавлять или удалять элементы).
1. *ngIf: Условный рендеринг
1.1. Базовое использование
<div \*ngIf="isVisible">Этот блок будет показан, если isVisible === true</div>
Если значение переменной isVisible в компоненте истинно (true), то элемент отобразится. Если false — не будет отображён вовсе (Angular удаляет элемент из DOM).
1.2. Альтернатива с else
Можно использовать ngIf с else для показа альтернативного шаблона:
<div \*ngIf="isLoggedIn; else guestBlock">Добро пожаловать, пользователь!</div>
<ng-template #guestBlock>Пожалуйста, войдите в систему</ng-template>
Здесь ng-template — специальный контейнер, который Angular не рендерит до тех пор, пока его не вызовет ngIf.
1.3. С then и else
Более гибкий синтаксис:
<ng-container \*ngIf="userLoaded; then userBlock; else loadingBlock"></ng-container>
<ng-template #userBlock>Данные пользователя загружены</ng-template>
<ng-template #loadingBlock>Загрузка данных...</ng-template>
1.4. Использование as для создания локальной переменной
<div \*ngIf="user as currentUser">
Имя: {{ currentUser.name }}
</div>
2. *ngFor: Повторение элементов
ngFor позволяет создавать шаблонный элемент для каждого объекта в массиве.
2.1. Базовое использование
<ul>
<li \*ngFor="let item of items">{{ item }}</li>
</ul>
Если items = ['a', 'b', 'c'], то Angular отобразит три элемента <li> с соответствующими значениями.
2.2. Использование индекса
<li \*ngFor="let item of items; let i = index">
{{ i + 1 }}. {{ item }}
</li>
Здесь переменная i содержит текущий индекс итерации, начиная с 0.
2.3. Использование дополнительных переменных
-
index — индекс текущего элемента
-
first — true, если это первый элемент
-
last — true, если это последний элемент
-
even — true, если индекс чётный
-
odd — true, если индекс нечётный
<div \*ngFor="let item of items; let isOdd = odd">
<span \[ngClass\]="{ 'odd-row': isOdd }">{{ item }}</span>
</div>
3. Вложенные ngFor
<div \*ngFor="let group of groups">
<h3>{{ group.name }}</h3>
<ul>
<li \*ngFor="let user of group.users">{{ user }}</li>
</ul>
</div>
В компоненте:
groups = \[
{ name: 'Админы', users: \['Анна', 'Олег'\] },
{ name: 'Пользователи', users: \['Иван', 'Мария'\] }
\];
4. Совмещение ngIf и ngFor
4.1. Через вложенные теги
<ul \*ngIf="items.length > 0">
<li \*ngFor="let item of items">{{ item }}</li>
</ul>
4.2. Через ng-container
ng-container используется для логических конструкций без добавления лишнего DOM:
<ng-container \*ngIf="items.length > 0">
<div \*ngFor="let item of items">{{ item }}</div>
</ng-container>
5. Работа с объектами
Angular не может напрямую итерироваться по объекту, только по массиву. Но можно преобразовать объект в массив:
objectEntries = Object.entries(myObject); // \[\['ключ1', 'значение1'\], ...\]
<div \*ngFor="let \[key, value\] of objectEntries">
{{ key }}: {{ value }}
</div>
6. Пример: Таблица с ngFor
<table>
<thead>
<tr><th>#</th><th>Имя</th><th>Email</th></tr>
</thead>
<tbody>
<tr \*ngFor="let user of users; let i = index">
<td>{{ i + 1 }}</td>
<td>{{ user.name }}</td>
<td>{{ user.email }}</td>
</tr>
</tbody>
</table>
7. Пример: ngIf + ngFor + trackBy
Когда Angular рендерит список через ngFor, он по умолчанию сравнивает объекты по ссылке, что может привести к перерендерингу всех элементов. Для оптимизации используется trackBy:
<li \*ngFor="let item of items; trackBy: trackById">{{ item.name }}</li>
trackById(index: number, item: any): any {
return item.id;
}
Это особенно полезно при работе с большими списками и динамически обновляемыми данными.
8. Использование ng-template с ngFor
Иногда нужно вынести шаблон итерации отдельно:
<ng-container \*ngFor="let item of items; template: itemTpl"></ng-container>
<ng-template #itemTpl let-item>
<div>{{ item.name }}</div>
</ng-template>
Альтернативно:
<ng-template ngFor let-item \[ngForOf\]="items">
<div>{{ item }}</div>
</ng-template>
9. Пример использования ngIf с загрузкой
<div \*ngIf="loading">Загрузка...</div>
<div \*ngIf="!loading && data">{{ data }}</div>
<div \*ngIf="!loading && !data">Нет данных</div>
10. Антипаттерн: Совмещение *ngIf и *ngFor на одном элементе
Такой код:
<li \*ngIf="condition" \*ngFor="let item of items">{{ item }}</li>
не будет работать, так как Angular не позволяет использовать две структурные директивы на одном элементе. Правильный способ — обернуть в <ng-container>:
<ng-container \*ngIf="condition">
<li \*ngFor="let item of items">{{ item }}</li>
</ng-container>
11. Управление DOM при помощи ngIf и ngFor
-
*ngIf физически удаляет и вставляет элемент в DOM.
-
*ngFor создает копии шаблона для каждого элемента массива.
-
В обоих случаях Angular отслеживает изменения с помощью ChangeDetectorRef, и любое изменение входных данных вызывает пересчёт DOM.
ngIf и ngFor являются основными инструментами Angular-шаблонов и обеспечивают гибкий контроль за отображением элементов в DOM. Их грамотное использование позволяет выстраивать эффективные, адаптивные и производительные пользовательские интерфейсы.