JavaRush /Курсы /Модуль 4: Node.js, Next.js и Angular /Структурные директивы: *ngIf...

Структурные директивы: *ngIf, сравнение с React

Модуль 4: Node.js, Next.js и Angular
14 уровень , 1 лекция
Открыта

1. Что такое структурные директивы?

Структурные директивы — это директивы, которые изменяют структуру DOM: добавляют или удаляют элементы в зависимости от условий. В Angular все структурные директивы начинаются с * (звёздочка), чтобы вы сразу могли их отличить от остальных.

Самые популярные структурные директивы в Angular:

  • *ngIf — условное отображение элементов
  • *ngFor — перебор коллекций (будет в следующей лекции)
  • *ngSwitch — переключение между вариантами (продвинутый случай)

В этой лекции нас интересует именно *ngIf.

Зачем нужен *ngIf?

В реальных приложениях вы часто сталкиваетесь с ситуацией: "Показывать или не показывать этот блок?". Например:

  • Кнопка "Войти" должна исчезнуть после входа пользователя.
  • Сообщение об ошибке появляется только если что-то пошло не так.
  • Блок загрузки показывается только во время загрузки данных.

Для всего этого в Angular есть *ngIf. Он работает как шлагбаум: если условие истинно — элемент появляется в DOM, если ложно — исчезает. Причём элемент реально удаляется из DOM, а не просто "прячется" стилями.

2. Как работает *ngIf? Примеры

Базовый синтаксис

<div *ngIf="условие">
  Этот блок появится, если условие истинно!
</div>
  • Если условиеtrue, блок появится на странице.
  • Если false — элемента не будет даже в DOM!

Пример 1: Простейшее использование

// app.component.ts
export class AppComponent {
  isLoggedIn = false;
}
<!-- app.component.html -->
<button *ngIf="!isLoggedIn">Войти</button>
<button *ngIf="isLoggedIn">Выйти</button>

Если пользователь не вошёл — будет кнопка "Войти". Вошёл — появится "Выйти". Всё просто!

Пример 2: Сообщение об ошибке

errorMessage: string | null = null;
<div *ngIf="errorMessage" class="error">
  {{ errorMessage }}
</div>

Если errorMessage не пустая строка и не null — блок появится и покажет текст ошибки.

3. Как работает *ngIf внутри?

Когда Angular видит *ngIf, он делает магию: превращает ваш элемент в специальный шаблон <ng-template>, который будет вставлен в DOM только если условие истинно. Если условие ложно — шаблон даже не попадает в DOM.

Визуализация

<div *ngIf="isVisible">Привет!</div>

Angular превращает это примерно в такое:

<ng-template [ngIf]="isVisible">
  <div>Привет!</div>
</ng-template>

То есть элемент не просто скрывается — его реально нет на странице, пока условие не станет истинным. Это экономит ресурсы и предотвращает случайные баги, связанные с "невидимыми" элементами.

4. Альтернатива: else в *ngIf

Иногда нужно показать что-то другое, если условие не выполнено. Для этого Angular поддерживает конструкцию else. Пример:

<div *ngIf="isLoading; else loadedBlock">
  Загрузка...
</div>
<ng-template #loadedBlock>
  <div>Данные загружены!</div>
</ng-template>
  • Если isLoadingtrue, будет "Загрузка...".
  • Если false — появится содержимое из шаблона #loadedBlock.

Более компактный пример

<div *ngIf="user; else guestBlock">
  Добро пожаловать, {{ user.name }}!
</div>
<ng-template #guestBlock>
  <div>Пожалуйста, войдите в систему.</div>
</ng-template>

5. Сравнение с React: "if" в JSX

В React нет встроенного аналога *ngIf, но условный рендеринг делается через обычный JavaScript.

Пример 1: Тернарный оператор

{isLoggedIn ? <button>Выйти</button> : <button>Войти</button>}

Пример 2: &&-оператор

{errorMessage && <div className="error">{errorMessage}</div>}

Пример 3: if-else перед return

let content;
if (isLoading) {
  content = <div>Загрузка...</div>;
} else {
  content = <div>Данные загружены!</div>;
}
return <>{content}</>;

Главное отличие:

  • В React вы пишете логику прямо на JavaScript внутри JSX.
  • В Angular — используете декларативную конструкцию в шаблоне (*ngIf).

Таблица сравнения

Angular (*ngIf) React (JSX)
<div *ngIf="isShown">...</div>
{isShown && <div>...</div>}
<div *ngIf="a; else b">A</div>
{a ? <div>A</div> : <div>B</div>}
Нет элемента в DOM, если false Нет элемента в DOM, если false
Условия — только выражения шаблона Можно любые JS-выражения

6. Вложенные *ngIf и блоки else if

В Angular нет прямого аналога else if для *ngIf. Но можно легко организовать вложенные условия через несколько блоков:

<div *ngIf="status === 'loading'">Загрузка...</div>
<div *ngIf="status === 'error'">Ошибка!</div>
<div *ngIf="status === 'success'">Успех!</div>

Или с использованием else и дополнительных шаблонов:

<div *ngIf="status === 'loading'; else notLoading">Загрузка...</div>
<ng-template #notLoading>
  <div *ngIf="status === 'error'; else successBlock">Ошибка!</div>
</ng-template>
<ng-template #successBlock>
  <div>Успех!</div>
</ng-template>

Честно говоря, если хочется много вложенных условий — проще вынести логику в компонент и сделать одну переменную, которую проверять.

7. Практика: добавляем условный рендеринг в ваше приложение

Допустим, мы делаем простое TODO-приложение и хотим показывать сообщение "Нет задач", если список пуст, и список задач — если не пуст.

Шаг 1. В компоненте

export class TodoComponent {
  todos: string[] = [];
}

Шаг 2. В шаблоне

<div *ngIf="todos.length === 0">
  Нет задач!
</div>
<ul *ngIf="todos.length > 0">
  <li *ngFor="let todo of todos">{{ todo }}</li>
</ul>

После добавления задачи

addTodo(task: string) {
  this.todos.push(task);
}

Результат:

  • Пока задач нет — видим "Нет задач!"
  • Как только добавили — появляется список.

8. Типичные ошибки при использовании *ngIf

Ошибка №1: Использование *ngIf вместе с hidden или display: none.
Если вы хотите полностью убрать элемент из DOM, используйте только *ngIf. Если добавить hidden или CSS-скрытие, элемент останется в DOM, а это не всегда безопасно (например, в формах).

Ошибка №2: Ожидание, что переменные сразу обновят DOM.
Иногда переменная меняется, но Angular не обновляет DOM мгновенно (например, если забыли про асинхронные операции). Если используете асинхронные данные — убедитесь, что они реально обновились.

Ошибка №3: Использование сложных выражений в *ngIf.
Лучше выносить сложные вычисления в переменные компонента, а не писать монстрообразные выражения в шаблоне. Так проще поддерживать код и легче отлаживать.

Ошибка №4: Дублирование кода в блоках *ngIf и else.
Если большая часть разметки совпадает — лучше сделать одну разметку и менять только отличающиеся части, чтобы не плодить копипасту.

Ошибка №5: Ожидание, что *ngIf работает как в React.
В React условный рендеринг — это просто про "вернуть или не вернуть компонент". В Angular — про "есть элемент в DOM или его нет". Иногда это влияет и на жизненный цикл дочерних компонентов (например, при уничтожении компонента через *ngIf его состояние сбрасывается).

Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ