Другое

Как использовать *ngIf else в Angular

Узнайте, как использовать *ngIf else в Angular для более чистого условного рендеринга. Изучите синтаксис, примеры, лучшие практики и преимущества производительности по сравнению с отдельными элементами *ngIf.

Как использовать *ngIf else в Angular?

Я работаю с Angular и хочу реализовать директиву *ngIf else (доступную начиная с версии 4) для условного отображения контента. В настоящее время я использую отдельные элементы div с противоположными условиями:

html
<div *ngIf="isValid">
  контент здесь ...
</div>

<div *ngIf="!isValid">
 другой контент здесь...
</div>

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

Директива *ngIf else в Angular позволяет более лаконично условно отображать контент, используя одно условие со ссылкой на шаблон else, что устраняет необходимость в отдельных элементах div с противоположными условиями. Этот синтаксис доступен с Angular 4 и обеспечивает лучшую производительность и более чистую структуру кода, сохраняя связанный условный контент вместе в ваших шаблонах. Вместо управления двумя отдельными директивами *ngIf с отрицательными условиями, вы можете использовать синтаксис *ngIf="condition; else templateName" в паре с элементом ng-template для определения контента запасного варианта.

Содержание

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

Фундаментальный синтаксис *ngIf else следует этому шаблону:

html
<div *ngIf="condition; else elseBlockName">
  <!-- Контент для отображения, когда условие истинно -->
  <p>Этот контент отображается, когда условие истинно</p>
</div>
<ng-template #elseBlockName>
  <!-- Контент для отображения, когда условие ложно -->
  <p>Этот контент отображается, когда условие ложно</p>
</ng-template>

Основные компоненты:

  • *ngIf="condition; else elseBlockName" - Основная директива с предложением else
  • <ng-template #elseBlockName> - Шаблон, содержащий контент запасного варианта
  • #elseBlockName создает переменную ссылки на шаблон, к которой может обращаться директива *ngIf

Как объясняется в документации Angular, “Когда выражение оценивается как истинное, Angular отображает шаблон, предоставленный в предложении then, а когда ложно или null, Angular отображает шаблон, предоставленный в необязательном предложении else.”

Работа с ng-template

Элемент ng-template является ключевым для функциональности *ngIf else. Это специальный элемент Angular, который интерпретируется во время выполнения, но сам не отображается в DOM.

Вот как это работает:

html
<!-- Пример аутентификации пользователя -->
<div *ngIf="isLoggedIn; else loginPrompt">
  <h2>Добро пожаловать обратно, пользователь!</h2>
  <p>Вы успешно вошли в систему.</p>
</div>

<ng-template #loginPrompt>
  <div class="login-container">
    <h2>Пожалуйста, войдите в систему для продолжения</h2>
    <button (click)="login()">Войти</button>
  </div>
</ng-template>

Как объясняется в уроке на malcoded.com, “ng-template - это специальный элемент, который интерпретируется Angular и не имеет соответствия в DOM. Это означает, что этот тег не включается в итоговый HTML-результат, а только его содержимое.”

Вы также можете использовать переменные шаблона для создания более сложных условных структур:

html
<div *ngIf="userRole === 'admin'; else userTemplate">
  <h2>Панель администратора</h2>
  <p>Добро пожаловать в административный интерфейс</p>
</div>

<ng-template #userTemplate>
  <div *ngIf="userRole === 'editor'; else guestTemplate">
    <h2>Панель редактора</h2>
    <p>Добро пожаловать в интерфейс редактирования</p>
  </div>
</ng-template>

<ng-template #guestTemplate>
  <h2>Публичный контент</h2>
  <p>Пожалуйста, войдите в систему для доступа к дополнительным функциям</p>
</ng-template>

Расширенные примеры и лучшие практики

Использование ngIf с предложениями then и else

Для большего контроля вы можете явно использовать предложение then:

html
<ng-template #adminTemplate let-user="user">
  <h2>Администратор: {{ user.name }}</h2>
  <p>Предоставлен полный административный доступ</p>
</ng-template>

<ng-template #defaultTemplate let-user="user">
  <h2>Добро пожаловать: {{ user.name }}</h2>
  <p>Стандартный пользовательский доступ</p>
</ng-template>

<div *ngIf="user; then adminTemplate; else defaultTemplate" [ngIfContext]="user">
</div>

Условный рендеринг на основе данных

Для сценариев, таких как отображение списков курсов или коллекций данных:

html
<div *ngIf="courses.length > 0; else noCoursesTemplate">
  <h2>Ваши курсы</h2>
  <ul>
    <li *ngFor="let course of courses">{{ course.name }}</li>
  </ul>
</div>

<ng-template #noCoursesTemplate>
  <div class="empty-state">
    <h2>Курсы недоступны</h2>
    <button (click)="browseCourses()">Обзор курсов</button>
  </div>
</ng-template>

Как объясняется в руководстве Angular University, “Помимо выражения courses.length, мы также можем передать в ngIf предложение else, которое указывает на ссылку на шаблон (шаблон noCourses в данном случае).”

Переменные контекста шаблона

Вы можете передавать переменные контекста в ваши шаблоны:

html
<ng-template #userTemplate let-user="user" let-role="role">
  <div class="user-card">
    <h3>{{ user.name }}</h3>
    <p>Роль: {{ role }}</p>
  </div>
</ng-template>

<div *ngIf="currentUser; then userTemplate; else guestTemplate" 
     [ngIfContext]="{user: currentUser, role: currentUser.role}">
</div>

Рекомендации по производительности

Синтаксис *ngIf else предлагает преимущества производительности по сравнению с использованием отдельных директив *ngIf с отрицательными условиями. Согласно результатам исследований, Angular 17+ показал “ускорение производительности времени выполнения до 90%” с этим подходом.

Ключевые преимущества производительности включают:

  • Единая оценка директивы: Вместо оценки двух отдельных условий *ngIf, Angular оценивает только одно условие и связанную с ним ссылку на шаблон
  • Лучшее обнаружение изменений: Фреймворк может более эффективно отслеживать изменения и обновлять DOM
  • Эффективность использования памяти: Только активный шаблон создается экземпляром и хранится в памяти

В обсуждении на Stack Overflow упоминается, что “с точки зрения производительности, я подозреваю, что первый вариант имеет 2 директивы, которые нужно оценивать независимо, в то время как другие 2 имеют только одну. Если бы у вас это было в списке/таблице из тысяч элементов, не было бы это медленнее?”

Миграция с отдельных элементов *ngIf

Миграция с текущего подхода с использованием отдельных элементов div проста:

До (текущий подход):

html
<div *ngIf="isValid">
  контент здесь ...
</div>

<div *ngIf="!isValid">
  другой контент здесь...
</div>

*После (использование ngIf else):

html
<div *ngIf="isValid; else invalidContent">
  контент здесь ...
</div>

<ng-template #invalidContent>
  другой контент здесь...
</ng-template>

Процесс миграции включает:

  1. Определение пар условий *ngIf, которые являются противоположными
  2. Выбор одного в качестве основного условия
  3. Создание ng-template для блока else
  4. Ссылка на шаблон в директиве *ngIf

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

Вот полный пример, показывающий компонент профиля пользователя с *ngIf else:

typescript
import { Component } from '@angular/core';

@Component({
  selector: 'app-user-profile',
  templateUrl: './user-profile.component.html'
})
export class UserProfileComponent {
  isLoggedIn = true;
  userRole = 'admin';
  isLoading = false;
  userProfile = null;

  constructor() {
    // Имитация загрузки данных пользователя
    setTimeout(() => {
      this.isLoading = false;
      this.userProfile = {
        name: 'John Doe',
        email: 'john@example.com',
        role: 'admin'
      };
    }, 2000);
  }

  logout() {
    this.isLoggedIn = false;
  }
}
html
<!-- user-profile.component.html -->
<div *ngIf="!isLoading; else loadingTemplate">
  <div *ngIf="isLoggedIn; else notLoggedInTemplate">
    <div *ngIf="userProfile.role === 'admin'; else regularUserTemplate">
      <h2>Панель администратора</h2>
      <p>Добро пожаловать обратно, {{ userProfile.name }}!</p>
      <button (click)="logout()">Выйти</button>
    </div>
    
    <ng-template #regularUserTemplate>
      <h2>Панель пользователя</h2>
      <p>Добро пожаловать обратно, {{ userProfile.name }}!</p>
      <p>Ваша роль: {{ userProfile.role }}</p>
      <button (click)="logout()">Выйти</button>
    </ng-template>
  </div>

  <ng-template #notLoggedInTemplate>
    <div class="login-prompt">
      <h2>Пожалуйста, войдите в систему для продолжения</h2>
      <p>Вам необходимо войти в систему для доступа к вашему профилю.</p>
    </div>
  </ng-template>
</div>

<ng-template #loadingTemplate>
  <div class="loading-spinner">
    <p>Загрузка вашего профиля...</p>
  </div>
</ng-template>

Этот пример демонстрирует:

  • Вложенные операторы *ngIf else
  • Состояния загрузки с ng-template
  • Условный рендеринг на основе роли пользователя
  • Четкое разделение различных состояний UI

Источники

  1. NgIf • Документация Angular
  2. Как использовать “*ngIf else” в Angular с примерами - OneClickITSolution
  3. Как использовать *ngIf else в Angular - malcoded.com
  4. Как можно использовать “*ngIf else”? - Medium от Daniel Martin
  5. Angulars NgIf, Else, Then - Объяснено - Ultimate Courses
  6. Angular ngIf: Полное руководство - Angular University
  7. Понимание *ngIf, *ngIf else, *ngIf then else - Medium от InterviewPro

Заключение

Директива *ngIf else обеспечивает более элегантный и производительный способ обработки условного рендеринга в приложениях Angular. Заменяя отдельные элементы div с противоположными условиями, вы можете достичь более чистого кода, который легче поддерживать и понимать. Ключевые преимущества включают лучшую производительность, улучшаемую читаемость и более эффективное обнаружение изменений. При реализации этого шаблона помните об использовании элементов ng-template для ваших блоков else и рассмотрите возможность использования переменных контекста шаблона для более сложных сценариев. Этот подход был усовершенствован в версиях Angular и продолжает улучшаться, с значительным повышением производительности в последних версиях, таких как Angular 17+.

Авторы
Проверено модерацией
Модерация