Модуль 12

Structural Directives: *ngIf, *ngFor, *ngSwitch

Ось готовий урок, створений за твоїм майстер-промптом.


🎓 Тема: Structural Directives (ngIf, ngFor, *ngSwitch)

(Стиль: David Malan / CS50)


1. 🔥 Вступ: Чому ми не показуємо все й одразу?

Уявіть, що ви зайшли на свій улюблений сайт — скажімо, інтернет-магазин чи соціальну мережу. Але замість звичної стрічки новин ви бачите абсолютно все, що є в коді сайту.

Ви бачите кнопку «Вийти», хоча ви навіть не увійшли. Ви бачите повідомлення «Ваш кошик порожній» і одночасно список товарів у кошику. Ви бачите панель адміністратора, хоча ви звичайний користувач.

Це був би хаос, правда? 🤯

У реальному житті, коли ви приходите в ресторан, офіціант не приносить вам одразу всі страви з меню на стіл, щоб ви вибрали. Він приносить меню (список), а страва з'являється на столі тільки якщо ви її замовили.

У веб-розробці ми маємо таку ж задачу. Нам потрібен механізм, який скаже HTML-сторінці: 1. Цей блок покажи, тільки якщо користувач залогінився. 2. Цей список товарів повтори стільки разів, скільки у нас є товарів у базі.

Без цього наші додатки були б статичними, нудними та перевантаженими. Саме тут на сцену виходять Структурні Директиви. Це інструменти Angular, які дозволяють нам бути архітекторами нашої сторінки в реальному часі.


2. 🧠 Теоретична база: Як це працює «під капотом»?

Давайте розберемося. Що таке директива? Грубо кажучи, це команда для Angular зробити щось з елементом DOM (частиною вашої сторінки).

Але чому вони називаються структурними? Тому що вони змінюють структуру DOM-дерева. Вони фізично додають або видаляють елементи з HTML, а не просто ховають їх.

Свята трійця, яку треба знати:

  1. *ngIf — "Я існую, тільки якщо умова істинна (true)".
  2. *ngFor — "Я розмножусь стільки разів, скільки елементів у списку".
  3. *ngSwitch — "Я виберу один варіант із багатьох (як перемикач)".

👀 Зверніть увагу на зірочку * перед назвою! Це не для краси. Це синтаксичний цукор. Вона каже Angular: "Ей, друже, тут буде змінюватися структура шаблону, будь уважний!". Без зірочки це працювати не буде (або працюватиме зовсім інакше).

Як це працює під капотом? Коли ви пишете <div *ngIf="false">...</div>, Angular не просто робить цьому блоку CSS-стиль display: none. Ні! Він повністю вирізає цей шматок коду з пам'яті браузера. Його там немає. Коли умова стає true, Angular створює його заново. Це важливо для продуктивності.


3. 🧪 Приклади: Від простого до реального

Приклад №1: *ngIf — Охоронець клубу

Уявіть, що у нас є змінна isLoggedIn = false.

<!-- Що ви очікуєте побачити на екрані? -->
<button *ngIf="!isLoggedIn">Увійти</button>
<button *ngIf="isLoggedIn">Вийти</button>

Результат: Ви побачите тільки кнопку "Увійти". Кнопки "Вийти" в HTML-коді сторінки навіть не існує. Якщо ми змінимо isLoggedIn = true, перша кнопка зникне (знищиться), а друга з'явиться.


Приклад №2: *ngFor — Список завдань

У нас є масив у компоненті: tasks = ['Купити хліб', 'Вивчити Angular', 'Поспати']

<ul>
  <!-- Angular, пройдись по tasks і для кожного item створи <li> -->
  <li *ngFor="let item of tasks">
     {{ item }}
  </li>
</ul>

Що тут відбувається? let item — це ми створюємо локальну змінну для кожного обертання циклу. Ми могли назвати її let task, let x або let pizza. Angular бере шаблон <li>...</li> і штампує його 3 рази.


Приклад №3: *ngSwitch — Світлофор

У нас є змінна color = 'yellow'.

<div [ngSwitch]="color">
  <p *ngSwitchCase="'red'">🔴 Стій!</p>
  <p *ngSwitchCase="'yellow'">🟡 Готуйся...</p>
  <p *ngSwitchCase="'green'">🟢 Їдь!</p>
  <p *ngSwitchDefault>⚫ Світлофор зламався</p>
</div>

Результат: На екрані буде тільки "🟡 Готуйся...". Зверніть увагу: на самому контейнері [ngSwitch] зірочки немає (це атрибут), а на варіантах *ngSwitchCase — є (бо вони додаються/видаляються).


4. 🛠 Практична частина

Час забруднити руки кодом! Відкривайте свій редактор.

🔹 Завдання 1: "Привид"

Створіть параграф <p>, який містить секретний текст. Додайте кнопку "Показати секрет". * Використовуйте змінну isVisible: boolean. * При кліку змінюйте її значення (toggle). * Використовуйте *ngIf на параграфі.

🔹 Завдання 2: "Список покупок"

У вашому компоненті створіть масив об'єктів: products = [{name: 'Apple', price: 20}, {name: 'Banana', price: 10}, {name: 'Audi', price: 50000}] * Виведіть їх список через *ngFor. * Показуйте назву і ціну.

🔹 Завдання 3: "Тільки для багатих" (Комбінація)

Використовуючи попередній список: * Додайте всередині циклу *ngFor умову *ngIf. * Якщо ціна товару більше 1000 — додайте поруч емодзі 💎 (діамант) або напис "VIP".

🔹 Завдання 4: Міні-кейс "Статус замовлення"

У вас є змінна status, яка може бути: 'pending', 'shipped', 'delivered', 'error'. Використовуючи *ngSwitch, виведіть повідомлення різного кольору для кожного статусу. * Pending -> "Очікуємо" (жовтий) * Shipped -> "В дорозі" (синій) * Delivered -> "Доставлено" (зелений) * Error -> "Помилка" (червоний)

🔹 Питання "А що, якщо..."

А що, якщо масив products порожній ([])? Що покаже *ngFor? (Спробуйте і переконайтесь, що нічого не зламається, просто буде порожньо). Як додати повідомлення "Список порожній", використовуючи *ngIf та products.length?


5. 💡 Мислення як у розробника

Ви вже майже профі, але є кілька граблів, на які наступають усі новачки. Давайте їх оминемо.

❌ Помилка №1: Два капітани на одному кораблі

Новачки часто намагаються написати так: <div *ngIf="isVisible" *ngFor="let item of items">...</div>

Angular скаже: "Error!". Не можна вішати дві структурні директиви на один елемент. Він не знає, що робити першим: перевіряти умову чи крутити цикл?

✅ Як думає профі: Він використовує обгортку. А ще краще — «невидиму» обгортку <ng-container>:

<ng-container *ngIf="isVisible">
  <div *ngFor="let item of items">...</div>
</ng-container>

<ng-container> не створює зайвого <div> у вашому HTML, він просто групує логіку.

❌ Помилка №2: *ngIf vs [hidden]

Можна сховати елемент через [hidden]="!isVisible". Це просто змінить CSS на display: none. * Якщо елемент "важкий" (графік, карта, відео) — краще *ngIf (повністю знищує, звільняє пам'ять). * Якщо елемент треба показати/сховати миттєво і часто (наприклад, випадаюче меню) — іноді [hidden] краще, бо браузеру не треба перемальовувати його з нуля.

🚀 Порада з практики: index

Іноді в циклі треба знати порядковий номер елемента. *ngFor дає нам бонус: <div *ngFor="let item of items; let i = index"> {{ i + 1 }}. {{ item }} </div> Завжди пам'ятайте про цей інструмент, коли треба нумерація!


6. 🧩 Підсумок

Отже, що ми сьогодні поклали у свій інструментарій?

  1. Ми навчилися керувати реальністю на сторінці: створювати та знищувати елементи за умовою (*ngIf).
  2. Ми навчилися масштабувати контент: перетворювати масиви даних на списки HTML (*ngFor).
  3. Ми навчилися перемикати варіанти відображення (*ngSwitch).

Тепер ви можете перетворити "сухий" масив даних на живий інтерактивний каталог товарів або список друзів.

Що далі? Уявіть, що ціна товару у вас 20, а ви хочете показати $20.00 або 20 ₴. Або ви хочете дату 2023-10-05 показати як "5 жовтня". Невже треба писати складні функції вручну? Ні! Наступного разу ми поговоримо про Pipes (Пайпи) — магічні фільтри для трансформації даних прямо в шаблоні.

А поки — вперед кодити! 💻🚀