Angular IDPStrong Junior
🔥 0

Модуль 2 · урок 9 з 15

Директиви

Директива — це поведінка, яку вішають на існуючий елемент. Компонент приносить свій шаблон, директива — ні: вона лише щось робить із тим, на чому висить. У таблиці ліда власна директива стоїть окремим пунктом, і це найшвидший спосіб показати, що ти розумієш Angular глибше за «намалював компонент».

Атрибутна директива

import { Directive, input, computed } from '@angular/core';

@Directive({
  selector: '[appOverdue]',            // вішається як атрибут
  host: {
    '[class.is-overdue]': 'overdue()',  // клас за умовою
    '[attr.aria-label]': 'label()',
  },
})
export class OverdueDirective {
  appOverdue = input.required<string | Date>();   // значення з того ж атрибута

  private readonly overdue = computed(() => new Date(this.appOverdue()) < new Date());
  private readonly label = computed(() => this.overdue() ? 'Прострочено' : null);
}
<tr [appOverdue]="task.dueDate">…</tr>

Об'єкт host — сучасна форма того, що раніше писали декораторами @HostBinding і @HostListener. Обидва варіанти живі:

// класичний вигляд — його ти зустрінеш у чужому коді
@Directive({ selector: '[appHighlight]' })
export class HighlightDirective {
  @HostBinding('class.is-hover') hovered = false;

  @HostListener('mouseenter') onEnter() { this.hovered = true; }
  @HostListener('mouseleave') onLeave() { this.hovered = false; }
}

Директива з доступом до елемента

import { Directive, ElementRef, inject, effect, input } from '@angular/core';

@Directive({ selector: '[appAutofocus]' })
export class AutofocusDirective {
  enabled = input(true, { alias: 'appAutofocus' });

  private el = inject(ElementRef<HTMLElement>);

  constructor() {
    effect(() => {
      if (this.enabled()) this.el.nativeElement.focus();
    });
  }
}
<input appAutofocus>
<input [appAutofocus]="isFirstField()">

Ось приклад, коли директива справді доречна: поведінку «постав фокус» треба чіпляти до різних елементів, і робити заради неї компонент безглуздо. У модулі 7 ця директива знадобиться в модалці.

Структурна директива

Структурна директива керує тим, чи існує елемент у DOM. Саме такими були *ngIf і *ngFor до появи @if і @for. Писати свої тепер доводиться рідко, але один випадок лишився корисним — приховування за правами доступу.

import { Directive, TemplateRef, ViewContainerRef, inject, input, effect } from '@angular/core';
import { AuthService } from '../../core/auth/auth.service';

@Directive({ selector: '[appIfRole]' })
export class IfRoleDirective {
  appIfRole = input.required<string>();

  private tpl = inject(TemplateRef<unknown>);
  private vcr = inject(ViewContainerRef);
  private auth = inject(AuthService);
  private shown = false;

  constructor() {
    effect(() => {
      const allowed = this.auth.hasRole(this.appIfRole());
      if (allowed && !this.shown) {
        this.vcr.createEmbeddedView(this.tpl);   // вставити шматок шаблону
        this.shown = true;
      } else if (!allowed && this.shown) {
        this.vcr.clear();                        // прибрати з DOM
        this.shown = false;
      }
    });
  }
}
<button *appIfRole="'producer'" (click)="remove()">Видалити</button>

Зірочка перед іменем — це скорочення. Angular розгортає його в <ng-template>, і саме тому директива отримує TemplateRef — заготовку розмітки, яку можна вставити або не вставити.

Приховати — не значить захистити

Директива прав ховає кнопку з інтерфейсу, але не забороняє дію. Хто завгодно може викликати метод із консолі або смикнути ендпоїнт напряму. Тому приховування — це зручність, а справжній захист — на бекенді. Про це варто сказати вголос, якщо на демо зайде мова про ролі: це рівно та відповідь, яку хоче почути тімлід.

Компонент, директива чи пайп

ПитанняВідповідь
Потрібна власна розмітка?Компонент
Треба додати поведінку до наявного елемента?Атрибутна директива
Треба вирішувати, чи існує елемент у DOM?Структурна директива — або просто @if
Треба лише відформатувати значення?Пайп
Що зробити для IDP

Для закриття пункту достатньо однієї атрибутної директиви, яку ти реально використовуєш. Найкорисніші кандидати: підсвітка прострочених рядків у таблиці, автофокус у модалці, або appIfRole для кнопок адміністратора. Головне — щоб вона була в ділі, а не лежала «для галочки».

≈ 45 хв · +25 XP за урок