Skip to content

Найпопулярніші запитання та відповіді на співбесіді з Angular

License

Notifications You must be signed in to change notification settings

DevLoversTeam/angular-interview-questions

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Angular

Найпопулярніші запитання та відповіді на співбесіді з Angular

1. Що таке Angular та які його ключові можливості?

Angular

Angular - це повноцінний frontend-фреймворк від Google для побудови масштабованих веб-додатків із підтримкою SPA, SSR, SSG та hybrid rendering.

Angular надає структурований підхід до розробки великих застосунків, включаючи архітектуру, маршрутизацію, управління станом і продуктивністю "out of the box".

Ключові можливості сучасного Angular:

  • Component-based architecture - декларативна побудова UI на основі компонентів.

  • Standalone Components - можливість створювати застосунки без жорсткої привʼязки до NgModules.

  • Reactivity (Signals + RxJS) - сучасна реактивна модель для роботи зі станом і асинхронними потоками даних.

  • Template control flow (@if, @for, @switch) - нативний, оптимізований синтаксис шаблонів.

  • Dependency Injection (DI) - потужна, tree-shakable система керування залежностями.

  • Routing & Lazy Loading - вбудована маршрутизація з підтримкою code splitting.

  • TypeScript-first - строга типізація та безпечна розробка за замовчуванням.

  • Rendering & Performance - оптимізований change detection, підтримка signal-based рендерингу та zoneless архітектури.

Коротко

Angular - це повноцінний framework, який покриває більшість потреб enterprise-рівня з коробки: від рендерингу та реактивності до маршрутизації, DI та оптимізації продуктивності.

2. Поясни, що таке data-binding в Angular та які є його типи?

Angular

  • Data-binding - це механізм синхронізації даних між компонентом і шаблоном.

Типи data-binding в Angular:

  1. Interpolation - одностороннє відображення даних у HTML:
<p>{{ userName }}</p>
  1. Property binding - передача значень у властивості DOM-елементів/компонентів:
<img [src]="avatarUrl" />
  1. Event binding - реакція на події DOM:
<button (click)="onSave()">Save</button>
  1. Two-way binding - синхронізація стану між шаблоном і компонентом ([(...)]):
<input [(ngModel)]="email" />

Коротко

В Angular доступні 4 основні типи зв’язування даних - interpolation, property binding, event binding, two-way binding.

3. Опиши архітектуру Angular-додатку.

Angular

  • Архітектура Angular базується на компонентному підході з чітким розділенням відповідальностей.

Основні елементи:

  • Компоненти (Standalone) - будівельні блоки UI, кожен має шаблон, стилі, логіку.

  • Сервіси - бізнес-логіка, робота з API, збереження стану; надаються через DI.

  • Signals - сучасний спосіб керування станом і реактивністю.

  • Control flow (@if, @for, @switch) - керування відображенням у шаблонах.

  • Router - маршрутизація між екранами без NgModules, з підтримкою lazy loading.

  • Dependency Injection - інжекція залежностей з різними scope (root, component, environment).

4. Що таке компонент в Angular та як він використовується?

Angular

  • Компонент - це основний будівельний блок Angular-додатку, що відповідає за частину UI та пов’язану з нею логіку.

Складається з:

  • класу (логіка, стан),

  • шаблону HTML,

  • стилів,

  • метаданих (selector, imports тощо).

Використання:

import { Component, signal } from '@angular/core';

@Component({
  selector: 'app-user-card',
  standalone: true,
  template: `
    <h3>{{ name() }}</h3>
    <button (click)="changeName()">Change</button>
  `
})
export class UserCardComponent {
  name = signal('Viktor');
  changeName() {
    this.name.set('Updated Name');
  }
}

У шаблоні іншого компонента можна підключити:

<app-user-card></app-user-card>

Коротко

Компонент = ізольований блок UI + логіка. В Angular він створюється як standalone, без NgModules.

5. Що таке директиви в Angular та які з них найчастіше використовуються?

Angular

  • Директива - це інструкція для DOM-елемента або компонента, яка змінює його поведінку чи вигляд.

Типи директив:

  • Structural (змінюють DOM):

    -@if (новий синтаксис замість *ngIf)

    • @for (новий синтаксис замість *ngFor)

    • @switch (альтернатива *ngSwitch)

  • Attribute (змінюють властивості/стилі елемента):

    • ngClass

    • ngStyle

    • ngModel

  • Custom directives - можна створювати свої для повторного використання логіки.

Коротко

Директиви в Angular = спосіб керувати DOM. Найчастіше - @if, @for, ngClass, ngStyle, ngModel.

6. Як створити сервіс в Angular і навіщо його використовують?

Angular

Сервіс - це клас із бізнес-логікою або функціоналом, який не пов’язаний напряму з UI.

Використовується для:

  • повторного використання коду,

  • роботи з API,

  • керування станом,

  • інкапсуляції логіки поза компонентом.

Приклад:

import { Injectable, signal } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class UserService {
  userName = signal('Guest');

  setUser(name: string) {
    this.userName.set(name);
  }
}

Використання у компоненті:

import { Component, inject } from '@angular/core';
import { UserService } from './user.service';

@Component({
  selector: 'app-header',
  standalone: true,
  template: `<h2>Welcome, {{ userService.userName() }}</h2>`
})
export class HeaderComponent {
  userService = inject(UserService);
}

Коротко

Сервіс створюють через @Injectable, а використовують для бізнес-логіки та спільного стану між компонентами.

7. Поясни, що таке dependency injection (DI) в Angular.

Angular

Dependency Injection (DI) - це механізм Angular, який автоматично створює та надає об’єкти (сервіси, токени) компонентам чи іншим сервісам замість ручного створення через new.

Навіщо:

  • спрощує тестування (можна підмінити залежності mock-ами),

  • забезпечує повторне використання сервісів,

  • керує життєвим циклом об’єктів (singleton, scoped).

Приклад:

import { Injectable } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class ApiService {
  getData() {
    return ['item1', 'item2'];
  }
}

Використання у компоненті:

import { Component, inject } from '@angular/core';
import { ApiService } from './api.service';

@Component({
  selector: 'app-list',
  standalone: true,
  template: `<li *ngFor="let item of data">{{ item }}</li>`
})
export class ListComponent {
  api = inject(ApiService);
  data = this.api.getData();
}

Коротко

DI в Angular = автоматичне надання залежностей (наприклад, сервісів) компонентам без new.

8. Що таке модуль в Angular і для чого він використовується?

Angular

  • У попередніх версіях Angular (до 15) модулі (NgModule) були обов’язковими для структурування застосунку. В Angular 20 модулі більше не потрібні, оскільки з’явилися standalone components.

Проте модулі ще існують і можуть застосовуватись для:

  • сумісності зі старим кодом,

  • групування функціоналу (напр. Angular Material ще має модулі),

  • поступової міграції на standalone API.

Приклад старого підходу:

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule],
  bootstrap: [AppComponent]
})
export class AppModule {}

Актуальний підхід (Angular 20, без модуля):

bootstrapApplication(AppComponent, {
  providers: []
});

Коротко

Модулі в Angular зараз - це легасі-інструмент, який замінено на standalone компоненти. Їхня головна роль сьогодні - лише для підтримки старого коду чи бібліотек.

9. Як обробляти події в Angular?

Angular

В Angular події обробляються через event binding, тобто підписку на подію DOM або кастомної події компонента.

Синтаксис:

<button (click)="onClick()">Click me</button>

У компоненті:

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

@Component({
  selector: 'app-button',
  standalone: true,
  template: `<button (click)="onClick()">Click me</button>`,
})
export class ButtonComponent {
  onClick() {
    console.log('Button clicked!');
  }
}

Кастомна подія (для дочірнього компонента):

import { Component, EventEmitter, Output } from '@angular/core';

@Component({
  selector: 'app-child',
  standalone: true,
  template: `<button (click)="notifyParent()">Notify</button>`
})
export class ChildComponent {
  @Output() notify = new EventEmitter<string>();
  notifyParent() {
    this.notify.emit('Hello from child');
  }
}

У батьківському компоненті:

<app-child (notify)="onNotify($event)"></app-child>

Коротко: в Angular події обробляються через (eventName)="handler()" для DOM та через @Output + EventEmitter для кастомних подій.

10. Що таке двостороннє зв’язування (two-way binding) і як його реалізувати в Angular?

Angular

Двостороннє зв’язування (two-way binding) - це синхронізація стану між компонентом і шаблоном, коли:

  • зміни в UI оновлюють стан компонента,
  • зміни в компоненті автоматично відображаються в UI.

Класичний підхід (ngModel, template-driven forms):

<input [(ngModel)]="name" />
<p>Hello, {{ name }}</p>
@Component({
  selector: 'app-input',
  standalone: true,
  template: `<input [(ngModel)]="name" />`
})
export class InputComponent {
  name = 'Evan';
}

Сучасний підхід з Signals (локальний стан):

import { Component, signal } from '@angular/core';

@Component({
  selector: 'app-input',
  standalone: true,
  template: `
    <input
      [value]="name()"
      (input)="name.set($any($event.target).value)"
    />
    <p>Hello, {{ name() }}</p>
  `
})
export class InputComponent {
  name = signal('Evan');
}

Signals забезпечують реактивність, але two-way binding тут реалізується вручну через event → set().

Two-way binding між компонентами з model():

import { Component, model } from '@angular/core';

@Component({
  selector: 'app-input',
  standalone: true,
  template: `
    <input
      [value]="name()"
      (input)="name.set($any($event.target).value)"
    />
  `
})
export class InputComponent {
  name = model('Evan');
}
<app-input [(name)]="userName"></app-input>

Коротко

  • ngModel - legacy two-way binding
  • signal() - сучасна реактивність (локальний стан)
  • model() - рекомендований спосіб two-way binding у сучасному Angular
11. Поясни різницю між компонентом і директивою в Angular?

Angular

  • Компонент

    • це спеціальний тип директиви, який має шаблон (HTML) + стилі + логіку;

    • використовується для створення UI-елементів;

    • приклад: @Component({ selector: 'app-user', template: '<p>User</p>' }).

  • Директива

    • не має власного шаблону;

    • змінює поведінку або вигляд існуючих елементів/компонентів;

    • може бути structural (@if, @for) або attribute (ngClass, ngStyle).

Приклад кастомної директиви (attribute):

import { Directive, ElementRef, Renderer2 } from '@angular/core';

@Directive({
  selector: '[highlight]',
  standalone: true
})
export class HighlightDirective {
  constructor(el: ElementRef, r: Renderer2) {
    r.setStyle(el.nativeElement, 'background', 'yellow');
  }
}

Використання у шаблоні:

<p highlight>Text with highlight</p>

Коротко

компонент = директива + шаблон, а директива = поведінка без власного UI.

12. Що таке пайпи (Pipes) в Angular та де їх варто використовувати?

Angular

Pipe - це клас, який трансформує дані без зміни їхнього оригінального стану. Використовується у шаблонах для форматування значень.

Приклади вбудованих пайпів:

  • date → форматування дат

  • currency → вивід валют

  • uppercase / lowercase → зміна регістру

  • async → робота з Promise / Observable

Приклад використання:

<p>{{ today | date:'dd/MM/yyyy' }}</p>
<p>{{ price | currency:'USD' }}</p>

Кастомний pipe:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'exclaim',
  standalone: true
})
export class ExclaimPipe implements PipeTransform {
  transform(value: string): string {
    return value + '!';
  }
}

У шаблоні:

<p>{{ 'Hello' | exclaim }}</p>
<!-- Hello! -->

Коротко

Pipes потрібні для форматування та трансформації даних у шаблоні, щоб не захаращувати логіку компонента.

13. Як обробляти надсилання форм (form submissions) в Angular?

Angular

В Angular є два основні підходи:

  1. Template-driven forms (простий варіант, з ngModel):
<form #form="ngForm" (ngSubmit)="onSubmit(form.value)">
  <input name="email" [(ngModel)]="email" required />
  <button type="submit">Send</button>
</form>
onSubmit(value: any) {
  console.log('Form submitted:', value);
}
  1. Reactive forms (рекомендований для складних кейсів):
import { Component } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';

@Component({
  selector: 'app-login',
  standalone: true,
  imports: [ReactiveFormsModule],
  template: `
    <form [formGroup]="form" (ngSubmit)="onSubmit()">
      <input formControlName="email" />
      <button type="submit">Login</button>
    </form>
  `
})
export class LoginComponent {
  form = new FormGroup({
    email: new FormControl('')
  });

  onSubmit() {
    console.log(this.form.value);
  }
}

Коротко

Форми в Angular обробляються через (ngSubmit) і бувають template-driven та reactive. Для простих форм можна брати ngModel, для великих і складних - reactive forms.

14. Що таке Angular CLI і для чого його використовують?

Angular

Angular CLI - це офіційний інструмент командного рядка для створення та керування Angular-проєктами.

Основні можливості:

  • ng new → створення нового застосунку

  • ng serve → локальний дев-сервер з hot reload

  • ng generate (ng g) → генерація компонентів, сервісів, пайпів, директив

  • ng build → продакшн-білд з оптимізацією

  • ng test, ng e2e → запуск тестів

  • ng add → інтеграція бібліотек (напр. Angular Material)

  • ng update → оновлення Angular до нової версії

Коротко: Angular CLI = швидкий старт, генерація коду, білд і управління життєвим циклом проєкту.

15. Як виконувати HTTP-запити в Angular за допомогою HttpClient ?

Angular

В Angular для роботи з HTTP використовується HttpClient, який надає методи get, post, put, delete тощо.

Кроки:

  1. Імпортувати HttpClientModule у bootstrapApplication.

  2. Інжектити HttpClient у сервіс чи компонент.

  3. Виконати запит і підписатися (або використовувати async pipe).

Приклад сервісу:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({ providedIn: 'root' })
export class ApiService {
  constructor(private http: HttpClient) {}

  getUsers() {
    return this.http.get('https://jsonplaceholder.typicode.com/users');
  }
}

Використання у компоненті:

import { Component, inject } from '@angular/core';
import { AsyncPipe, NgFor } from '@angular/common';
import { ApiService } from './api.service';

@Component({
  selector: 'app-users',
  standalone: true,
  imports: [NgFor, AsyncPipe],
  template: `
    <ul>
      <li *ngFor="let user of users$ | async">{{ user.name }}</li>
    </ul>
  `
})
export class UsersComponent {
  api = inject(ApiService);
  users$ = this.api.getUsers();
}

Коротко

В Angular 20 HTTP-запити робляться через HttpClient, а результат часто обробляється в шаблоні через async pipe.

16. Як передати дані з батьківського компонента до дочірнього?

Angular

Передача даних відбувається через input-зв’язування (@Input() декоратор). Батьківський компонент передає значення дочірньому через атрибут у шаблоні.

Приклад:

child.component.ts

import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-child',
  standalone: true,
  template: `<p>Message: {{ message }}</p>`
})
export class ChildComponent {
  @Input() message = '';
}

parent.component.ts

import { Component } from '@angular/core';
import { ChildComponent } from './child.component';

@Component({
  selector: 'app-parent',
  standalone: true,
  imports: [ChildComponent],
  template: `<app-child [message]="parentMessage"></app-child>`
})
export class ParentComponent {
  parentMessage = 'Hello from Parent!';
}

Коротко:

  • Дані від батька до дитини передаються через @Input() - це property binding [property]="value".
17. Як передати подію або дані від дочірнього компонента до батьківського?

Angular

Для передачі подій вгору використовується @Output() разом із EventEmitter. Дочірній компонент «викидає» подію, а батьківський підписується на неї через (eventName) у шаблоні.

child.component.ts

import { Component, EventEmitter, Output } from '@angular/core';

@Component({
  selector: 'app-child',
  standalone: true,
  template: `<button (click)="sendMessage()">Send</button>`
})
export class ChildComponent {
  @Output() message = new EventEmitter<string>();

  sendMessage() {
    this.message.emit('Hello from Child!');
  }
}

parent.component.ts

import { Component } from '@angular/core';
import { ChildComponent } from './child.component';

@Component({
  selector: 'app-parent',
  standalone: true,
  imports: [ChildComponent],
  template: `<app-child (message)="onMessage($event)"></app-child>`
})
export class ParentComponent {
  onMessage(data: string) {
    console.log('Received from child:', data);
  }
}

Коротко

Передача даних child → parent відбувається через @Output() і (event) binding. Дитина емітить подію, батько слухає.

18. Які є життєві цикли (lifecycle hooks) компонентів в Angular і що вони означають?

Angular

Lifecycle hooks - це методи, які Angular викликає на різних етапах «життя» компонента: створення, оновлення, знищення.

Основні хуки Angular:

Хук Коли викликається Типове використання
ngOnChanges(changes) Коли змінюються @Input властивості Реакція на зміни вхідних даних від батьківського компонента
ngOnInit() Один раз після ініціалізації компоненту Ініціалізація даних, запитів до API
ngDoCheck() На кожній зміні (детекції) Кастомна логіка перевірки змін
ngAfterContentInit() Один раз після вставлення контенту (ng-content) Робота з проєктованим контентом
ngAfterContentChecked() Після кожної перевірки контенту Оновлення після змін у проєктованому контенті
ngAfterViewInit() Один раз після ініціалізації view (дочірніх компонентів) Доступ до елементів через ViewChild/ViewChildren
ngAfterViewChecked() Після кожної перевірки view Оновлення DOM після перевірки
ngOnDestroy() Перед знищенням компоненту Очищення підписок, таймерів, ресурсів

Приклад:

import { Component, OnInit, OnDestroy } from '@angular/core';

@Component({
  selector: 'app-demo',
  standalone: true,
  template: `<p>Lifecycle demo</p>`
})
export class DemoComponent implements OnInit, OnDestroy {
  ngOnInit() {
    console.log('Component initialized');
  }

  ngOnDestroy() {
    console.log('Component destroyed');
  }
}

Коротко

Lifecycle hooks - це хуки життєвого циклу компонента, які дають змогу реагувати на створення, оновлення та знищення елемента.

19. Що таке ViewEncapsulation в Angular і для чого воно використовується?

Angular

ViewEncapsulation - це механізм інкапсуляції стилів у Angular, який визначає, як CSS компоненту впливає на DOM (чи лише на цей компонент, чи на весь застосунок).

Тип інкапсуляції Опис Особливість
Emulated (default) Angular імітує поведінку Shadow DOM, додаючи унікальні атрибути до елементів. Стилі діють лише всередині цього компонента.
ShadowDom Використовує нативний Shadow DOM браузера. Повна ізоляція стилів, немає витоку назовні.
None Без інкапсуляції. Стилі поширюються глобально на весь застосунок.

Приклад:

import { Component, ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'app-example',
  templateUrl: './example.component.HTML',
  styleUrls: ['./example.component.css'],
  encapsulation: ViewEncapsulation.ShadowDom
})
export class ExampleComponent {}

Коротко:

ViewEncapsulation контролює межі застосування CSS - чи стилі “ізольовані” всередині компонента, чи поширюються глобально. У більшості випадків - використовується Emulated.

20. Як застосовувати умовне (conditional) стилювання в Angular-компонентах?

Angular

  • В Angular умовне стилювання реалізується через директиви прив’язки стилів та класів - ngClass і ngStyle.
Метод Приклад Опис
[ngClass] <div [ngClass]="{ 'active': isActive, 'disabled': !isActive }"></div> Додає або забирає CSS-класи залежно від умови.
[ngStyle] <div [ngStyle]="{ 'color': isActive ? 'green' : 'red' }"></div> Застосовує стилі напряму через об’єкт.
Класова прив’язка <div [class.active]="isActive"></div> Додає клас, якщо умова true.
Стильова прив’язка <div [style.backgroundColor]="isActive ? 'blue' : 'gray'"></div> Змінює конкретний CSS-властивість залежно від умови.

Коротко:

Використовуй ngClass для керування класами та ngStyle або [style.prop] для динамічних inline-стилів. Це дає повний контроль над виглядом елементів залежно від стану компонента.

21. У чому різниця між структурними та атрибутними директивами в Angular?

Angular

  • Директиви в Angular бувають структурні та атрибутні, і вони впливають на DOM по-різному.
Тип директиви Опис Приклади Вплив на DOM
Структурна (Structural) Змінює структуру DOM - додає, видаляє або змінює елементи. *ngIf, *ngFor, *ngSwitchCase Створює або прибирає елементи в дереві DOM.
Атрибутна (Attribute) Змінює вигляд або поведінку наявного елемента. ngClass, ngStyle, ngModel, кастомні директиви (наприклад, appHighlight) Не змінює структуру DOM, лише властивості або стилі елемента.

Коротко:

Структурні директиви керують тим, що є в DOM, атрибутні директиви - тим, як це виглядає або поводиться.

22. Як створити власну структурну директиву в Angular?

Angular

Структурна директива змінює DOM (додає або видаляє елементи). Щоб створити кастомну структурну директиву:

Крок Опис
1 Створити директиву з декоратором @Directive і standalone: true.
2 Інжектити TemplateRef і ViewContainerRef для доступу до шаблону та контейнера.
3 Створити метод або сеттер, який вирішує, коли вставляти або видаляти шаблон.
4 Використовувати директиву через *yourDirective у шаблоні.

Приклад кастомної структурної директиви:

import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[appUnless]',
  standalone: true
})
export class UnlessDirective {
  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef
  ) {}

  @Input() set appUnless(condition: boolean) {
    this.viewContainer.clear();
    if (!condition) {
      this.viewContainer.createEmbeddedView(this.templateRef);
    }
  }
}

Використання у шаблоні:

<p *appUnless="isLoggedIn">You are not logged in!</p>

Коротко:

Кастомна структурна директива керує DOM через ViewContainerRef і TemplateRef. Використовується з * синтаксисом у шаблоні.

23. Як зробити сервіс singleton в Angular?

Angular

У Angular singleton-сервіс - це сервіс, який створюється лише один раз і використовується у всьому застосунку. Для цього потрібно вказати, де він надається (provided).

Спосіб Приклад Пояснення
1. Через providedIn: 'root' @Injectable({ providedIn: 'root' }) Найпоширеніший спосіб. Сервіс реєструється в головному інжекторі, створюється один раз для всього застосунку.
2. Через модуль (deprecated підхід) Додати в providers масив модуля (@NgModule) Використовується рідше. Сервіс буде singleton лише в межах цього модуля.
3. Через компонент (локальний інжектор) Додати в providers масив компонента Сервіс не буде singleton - створюється новий екземпляр для кожного компонента.

Приклад:

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  private token = '';
  setToken(t: string) { this.token = t; }
  getToken() { return this.token; }
}

Коротко:

Найкраща практика - @Injectable({ providedIn: 'root' }), бо це гарантує singleton-поведінку і оптимізує tree-shaking.

24. Як використовувати Observables у сервісах для обміну даними між компонентами?

Angular

Observables у сервісах дозволяють реактивно ділитися даними між компонентами - без прямої передачі через @Input() чи @Output().

Підхід Опис Типовий випадок використання
Subject Дає змогу як передавати (next()), так і підписуватись (subscribe()) на дані. Динамічне оновлення стану між компонентами.
BehaviorSubject Зберігає останнє значення, яке автоматично отримують нові підписники. Поточний стан (наприклад, авторизація, вибраний користувач).
ReplaySubject Передає певну кількість останніх значень новим підписникам. Історія подій або кешування даних.

Приклад (через BehaviorSubject):

data.service.ts

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class DataService {
  private messageSource = new BehaviorSubject<string>('Hello');
  message$ = this.messageSource.asObservable();

  updateMessage(newMsg: string) {
    this.messageSource.next(newMsg);
  }
}

component-a.ts

@Component({...})
export class ComponentA {
  constructor(private dataService: DataService) {}
  sendMessage() {
    this.dataService.updateMessage('Message from A');
  }
}

component-b.ts

@Component({...})
export class ComponentB {
  message = '';
  constructor(private dataService: DataService) {
    this.dataService.message$.subscribe(msg => this.message = msg);
  }
}

Коротко:

Сервіс з Subject або BehaviorSubject діє як “shared data channel” - один компонент надсилає дані, інші підписуються. Це реактивний і чистий спосіб обміну станом між компонентами.

25. Які існують способи надання (provide) сервісу в Angular і чим вони відрізняються?

Angular

  • У Angular є кілька способів оголосити, де і як створюється сервіс. Від цього залежить область його дії (scope) - чи він буде singleton, чи матиме локальний екземпляр.
Спосіб Як реалізується Область дії Коментар
1. providedIn: 'root' У декораторі @Injectable({ providedIn: 'root' }) Глобальна (один екземпляр у всьому застосунку) ✅ Найкраща практика. Оптимізується tree-shaking.
2. providedIn: 'platform' Через @Injectable({ providedIn: 'platform' }) Спільний сервіс між кількома Angular застосунками на одній сторінці Рідко використовується.
3. providedIn: 'any' Через @Injectable({ providedIn: 'any' }) Новий екземпляр для кожного lazy-loaded модуля Корисно для ізольованих модулів.
4. У providers масиві модуля (@NgModule) Додавання сервісу в providers Тільки в межах цього модуля Використовується в legacy-проєктах.
5. У providers масиві компонента providers: [MyService] у декораторі @Component Новий екземпляр для кожного екземпляра компонента Для локального стану або ізольованої логіки.

Приклад:

@Injectable({
  providedIn: 'root'
})
export class UserService {}

або

@Component({
  selector: 'app-profile',
  providers: [UserService]
})
export class ProfileComponent {}

Коротко:

Найчастіше використовується providedIn: 'root' - це дає один спільний екземпляр (singleton). Інші способи - для lazy-loading, ізоляції або особливих випадків.

26. Поясни, що таке providedIn у сервісах Angular і яку роль воно відіграє?

Angular

  • providedIn - це параметр у декораторі @Injectable, який визначає, де Angular має зареєструвати сервіс у DI (Dependency Injection) системі. Від нього залежить область дії (scope) сервісу та кількість створених екземплярів.
Значення providedIn Опис Область дії Використання
'root' Сервіс реєструється у головному інжекторі застосунку. Глобальна (singleton у всьому застосунку). ✅ Найпоширеніший і рекомендований спосіб.
'platform' Один інжектор для всієї платформи (кілька Angular app на сторінці). Спільний між застосунками. Рідкісний випадок використання.
'any' Кожен lazy-loaded модуль отримує власний екземпляр. Локальна для модуля або компонента. Для незалежних частин застосунку.
Клас або модуль (SomeModule) Сервіс буде створено лише в межах цього модуля. Локальна. Використовується для модульної ізоляції.

Приклад:

@Injectable({
  providedIn: 'root'
})
export class LoggerService {
  log(message: string) {
    console.log(`[LOG]: ${message}`);
  }
}

Коротко:

providedIn визначає, де саме Angular створює сервіс і чи буде він спільним (singleton). У більшості випадків використовують providedIn: 'root' - це просто, ефективно і підтримує tree-shaking.

27. Як у Angular використовувати HttpClient для обробки JSON-даних?

Angular

HttpClient - це сервіс Angular для виконання HTTP-запитів. Він автоматично перетворює JSON-відповіді в об’єкти JavaScript, тому додаткового парсингу не потрібно.

Крок Опис
1 Імпортуй HttpClientModule у кореневий або standalone компонент.
2 Інжектуй HttpClient у сервіс або компонент.
3 Використовуй методи get(), post(), put(), delete() тощо.
4 Angular автоматично обробляє JSON через RxJS Observable.

Приклад:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

export interface User {
  id: number;
  name: string;
  email: string;
}

@Injectable({ providedIn: 'root' })
export class UserService {
  private apiUrl = 'https://jsonplaceholder.typicode.com/users';

  constructor(private http: HttpClient) {}

  getUsers(): Observable<User[]> {
    return this.http.get<User[]>(this.apiUrl);
  }

  addUser(user: User): Observable<User> {
    return this.http.post<User>(this.apiUrl, user);
  }
}

component.ts

@Component({...})
export class AppComponent {
  users$ = this.userService.getUsers();

  constructor(private userService: UserService) {}
}

Особливості:

  • HttpClient автоматично парсить JSON у JS-об’єкти.

  • Можна вказати generic тип (<User[]>), щоб отримати типізовану відповідь.

  • Повертає Observable, тому можна застосовувати оператори RxJS (map, catchError, тощо).

Коротко:

HttpClient - це зручний API для роботи з JSON у Angular. Він типізований, реактивний і не потребує ручного JSON.parse().

28. Як обробляти REST API-запити та помилки у сервісах Angular?

Angular

  • REST-запити в Angular виконуються через HttpClient, а обробка помилок - через RxJS оператор catchError. Усе це зазвичай інкапсулюється в окремому сервісі, щоб компоненти залишалися “чистими”.
Крок Опис
1 Створи сервіс (@Injectable) і підключи HttpClient.
2 Використовуй методи get(), post(), put(), delete().
3 Обгорни запити у pipe() з catchError() для обробки помилок.
4 Поверни типізований Observable, щоб компонент міг підписатися.

Приклад:

import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { catchError, throwError, Observable } from 'rxjs';

export interface Product {
  id: number;
  name: string;
  price: number;
}

@Injectable({ providedIn: 'root' })
export class ProductService {
  private apiUrl = 'https://api.example.com/products';

  constructor(private http: HttpClient) {}

  getProducts(): Observable<Product[]> {
    return this.http.get<Product[]>(this.apiUrl).pipe(
      catchError(this.handleError)
    );
  }

  addProduct(product: Product): Observable<Product> {
    return this.http.post<Product>(this.apiUrl, product).pipe(
      catchError(this.handleError)
    );
  }

  private handleError(error: HttpErrorResponse) {
    if (error.status === 0) {
      console.error('Network error:', error.error);
    } else {
      console.error(`API returned code ${error.status}:`, error.error);
    }
    return throwError(() => new Error('Something went wrong; please try again.'));
  }
}

Пояснення:

  • catchError() - RxJS оператор для перехоплення помилок.

  • throwError() - створює новий стрім з помилкою.

  • Обробку логіки (try again, notify user, log error) краще робити всередині сервісу, не в компоненті.

Коротко:

  • REST API виклики обробляються у сервісі через HttpClient. Для помилок використовуй catchError() у поєднанні з власним handleError() методом - це робить код чистим і передбачуваним.
29. Як налаштовується маршрутизація (routing) в Angular-застосунках?

Angular

Routing в Angular визначає, який компонент відображається при переході на певний URL. Він налаштовується через масив маршрутів і RouterModule (або provideRouter для standalone API).

Крок Опис
1 Створити масив маршрутів (Routes[]), де кожен об’єкт описує шлях і компонент.
2 Імпортувати RouterModule.forRoot(routes) або використати provideRouter(routes) у main.ts.
3 Додати <router-outlet> у шаблон, щоб рендерити активний маршрут.
4 Використовувати директиви [routerLink] для навігації.

Приклад (standalone routing):

app.routes.ts

import { Routes } from '@angular/router';
import { HomeComponent } from './home.component';
import { AboutComponent } from './about.component';

export const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'about', component: AboutComponent },
  { path: '**', redirectTo: '' } // catch-all
];

main.ts

import { bootstrapApplication } from '@angular/platform-browser';
import { provideRouter } from '@angular/router';
import { AppComponent } from './app.component';
import { routes } from './app.routes';

bootstrapApplication(AppComponent, {
  providers: [provideRouter(routes)]
});

app.component.HTML

<nav>
  <a routerLink="/">Home</a>
  <a routerLink="/about">About</a>
</nav>

<router-outlet></router-outlet>

Додаткові можливості:

  • Route Guards (canActivate, canDeactivate) - для захисту маршрутів.

  • Lazy Loading - динамічне підвантаження модулів або компонентів.

  • Route Parameters (:id) - для передачі динамічних значень у маршруті.

Коротко:

Маршрутизація в Angular конфігурується через масив Routes і RouterModule або provideRouter(). Компоненти рендеряться у <router-outlet>, а переходи виконуються через [routerLink].

30. Як у Angular створити маршрут, який динамічно завантажує модуль лише під час доступу до нього (lazy loading)?

Angular

Так, у сучасному Angular (v16–20) це робиться через lazy loading з використанням динамічного import() у файлі маршрутизації. Це дозволяє не включати модуль у основний bundle, а завантажувати його лише при навігації.

Приклад:

// app.routes.ts (Angular 17+ standalone API)
import { Routes } from '@angular/router';

export const routes: Routes = [
  {
    path: 'admin',
    loadChildren: () =>
      import('./admin/admin.routes').then(m => m.ADMIN_ROUTES),
  },
];

У випадку standalone-компонентів:

{
  path: 'dashboard',
  loadComponent: () =>
    import('./dashboard/dashboard.component').then(c => c.DashboardComponent),
}

Коротко:

  • loadChildren або loadComponent використовуються для lazy loading.
  • Модуль/компонент завантажується лише при першому переході на відповідний маршрут.
  • Це оптимізує стартову швидкість застосунку.
31. Що таке RouterOutlet в Angular і як його використовують?

Angular

  • <router-outlet> - це директива, яка визначає місце у шаблоні, куди Angular підставляє компонент, що відповідає активному маршруту. Вона є “контейнером” для відображення контенту згідно з конфігурацією маршрутизатора.

Приклад:

<!-- app.component.HTML -->
<nav>
  <a routerLink="/home">Home</a>
  <a routerLink="/about">About</a>
</nav>

<router-outlet></router-outlet>
// app.routes.ts
import { Routes } from '@angular/router';
import { HomeComponent } from './home.component';
import { AboutComponent } from './about.component';

export const routes: Routes = [
  { path: 'home', component: HomeComponent },
  { path: 'about', component: AboutComponent },
];

Коротко:

  • RouterOutlet - точка вставки для компонентів маршруту.
  • Підтримує вкладені маршрути (може бути кілька router-outlet).
  • Без нього маршрути не відображаються у DOM.
32. Як у Angular застосовуються route guards (захисники маршрутів)?

Angular

  • Route guards - це сервіси, які контролюють доступ до маршрутів. Вони реалізують спеціальні інтерфейси (CanActivate, CanDeactivate, CanLoad, CanMatch, Resolve) і використовуються в конфігурації маршрутизатора.

Приклад (CanActivate):

// auth.guard.ts
import { CanActivateFn } from '@angular/router';

export const authGuard: CanActivateFn = (route, state) => {
  const isLoggedIn = !!localStorage.getItem('token');
  return isLoggedIn; // або redirectUrl при потребі
};
// app.routes.ts
export const routes = [
  {
    path: 'dashboard',
    canActivate: [authGuard],
    loadComponent: () =>
      import('./dashboard/dashboard.component').then(c => c.DashboardComponent),
  },
];

Коротко:

  • Guards перевіряють, чи можна активувати, завантажити або покинути маршрут.
  • Починаючи з Angular 15+, зручно використовувати функціональні guards (CanActivateFn) без класів.
  • Повертають true/false, UrlTree, або Observable/Promise.
33. Для чого в Angular використовується ActivatedRoute у маршрутизації?

Angular

ActivatedRoute дає доступ до інформації про поточний активний маршрут, включно з параметрами, query-параметрами, фрагментами URL і даними, переданими через data. Використовується всередині компонентів для отримання контексту маршруту.

Приклад:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-user',
  template: `<p>User ID: {{ userId }}</p>`
})
export class UserComponent implements OnInit {
  userId!: string;

  constructor(private route: ActivatedRoute) {}

  ngOnInit() {
    // отримати параметр з URL
    this.userId = this.route.snapshot.paramMap.get('id')!;

    // або підписка на зміни параметрів
    this.route.paramMap.subscribe(params => {
      this.userId = params.get('id')!;
    });
  }
}

Коротко:

  • ActivatedRoute - доступ до параметрів маршруту, query-параметрів, fragment і data.
  • Потрібен для динамічного завантаження даних залежно від маршруту.
  • Працює як зі snapshot, так і з Observable для реактивного оновлення.
34. Що таке параметри маршруту в Angular і як до них звертатися?

Angular

Параметри маршруту - це змінні частини URL, які визначаються у маршрутах та дозволяють передавати дані у компонент.

Приклад:

// app.routes.ts
import { Routes } from '@angular/router';
import { UserComponent } from './user.component';

export const routes: Routes = [
  { path: 'user/:id', component: UserComponent },
];
// user.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-user',
  template: `<p>User ID: {{ userId }}</p>`
})
export class UserComponent implements OnInit {
  userId!: string;

  constructor(private route: ActivatedRoute) {}

  ngOnInit() {
    // Через snapshot (одноразово)
    this.userId = this.route.snapshot.paramMap.get('id')!;

    // Через Observable (реактивно при зміні маршруту)
    this.route.paramMap.subscribe(params => {
      this.userId = params.get('id')!;
    });
  }
}

Коротко:

  • Route parameters - частина URL (наприклад, /user/123id = 123).
  • Доступ через ActivatedRoute.snapshot.paramMap або ActivatedRoute.paramMap.subscribe().
  • Використовуються для динамічного рендерингу контенту.
35. Як у Angular заздалегідь завантажити дані перед переходом на маршрут (resolve data)?

Angular

Для цього використовують Route Resolver - сервіс, який реалізує інтерфейс Resolve<T>. Angular чекає, поки resolver отримає дані, і передає їх у компонент через ActivatedRoute.data.

Приклад:

// user.resolver.ts
import { Injectable } from '@angular/core';
import { Resolve } from '@angular/router';
import { UserService } from './user.service';

@Injectable({ providedIn: 'root' })
export class UserResolver implements Resolve<any> {
  constructor(private userService: UserService) {}

  resolve() {
    return this.userService.getUser(); // може повертати Observable або Promise
  }
}
// app.routes.ts
import { Routes } from '@angular/router';
import { UserComponent } from './user.component';
import { UserResolver } from './user.resolver';

export const routes: Routes = [
  {
    path: 'user/:id',
    component: UserComponent,
    resolve: { userData: UserResolver }
  }
];
// user.component.ts
ngOnInit() {
  this.route.data.subscribe(data => {
    console.log(data.userData); // доступ до preload-даних
  });
}

Коротко:

  • Resolver завантажує дані перед активацією маршруту.
  • Повертає Observable, Promise або просте значення.
  • Дані доступні через ActivatedRoute.data у компоненті.
36. Як реалізувати lazy loading модулів або компонентів у Angular?

Angular

Lazy loading дозволяє завантажувати модулі чи компоненти тільки при переході на відповідний маршрут, щоб зменшити початковий розмір bundle.

Приклад для модуля (loadChildren):

// app.routes.ts
import { Routes } from '@angular/router';

export const routes: Routes = [
  {
    path: 'admin',
    loadChildren: () =>
      import('./admin/admin.module').then(m => m.AdminModule),
  },
];

Приклад для standalone-компонента (loadComponent):

{
  path: 'dashboard',
  loadComponent: () =>
    import('./dashboard/dashboard.component').then(c => c.DashboardComponent),
}

Коротко:

  • loadChildren - для lazy loading модулів.
  • loadComponent - для lazy loading standalone-компонентів (Angular 15+).
  • Підвищує швидкість старту додатку, завантажуючи код лише за потреби.
37. Поясни різницю між Template-driven та Reactive формами в Angular.

Angular

  • Template-driven форми будуються переважно у HTML-шаблоні за допомогою директив (ngModel, ngForm). Вони простіші, підходять для невеликих форм, але менш контрольовані - логіка зосереджена у шаблоні.

  • Reactive форми створюються в TypeScript-коді за допомогою FormGroup, FormControl, FormBuilder. Вони більш предиктивні, масштабовані й краще підходять для складних форм, валідації та тестування.

Приклад:

Template-driven:

<form #form="ngForm">
  <input name="email" ngModel required />
</form>

Reactive:

form = new FormGroup({
  email: new FormControl('', { nonNullable: true, validators: [Validators.required] })
});
<form [formGroup]="form">
  <input formControlName="email" />
</form>

Коротко:

  • Template-driven - декларативний підхід у шаблоні.
  • Reactive - імперативний підхід у коді, з повним контролем над станом форми.
38. Як виконується валідація користувацького введення у формах Angular?

Angular

В Angular є вбудована, кастомна та асинхронна валідація. Валідація визначається або через HTML-атрибути (у Template-driven формах), або через Validators у Reactive формах.

Reactive форма з валідацією:

form = new FormGroup({
  email: new FormControl('', {
    nonNullable: true,
    validators: [Validators.required, Validators.email]
  }),
  password: new FormControl('', {
    validators: [Validators.required, Validators.minLength(6)]
  })
});

HTML:

<form [formGroup]="form">
  <input formControlName="email" />
  <div *ngIf="form.controls.email.invalid && form.controls.email.touched">
    Invalid email
  </div>
</form>

Кастомний валідатор (приклад):

function forbiddenNameValidator(control: FormControl) {
  return control.value === 'admin' ? { forbiddenName: true } : null;
}

Асинхронний валідатор (приклад):

function emailExistsValidator(service: UserService): AsyncValidatorFn {
  return control => service.checkEmail(control.value).pipe(
    map(exists => (exists ? { emailTaken: true } : null))
  );
}

Коротко:

  • Використовуємо Validators (built-in або custom).
  • Реактивний підхід дає більше контролю й гнучкості для відображення помилок та асинхронних перевірок.
39. Як динамічно додавати або видаляти елементи управління (form controls) у Reactive Forms в Angular?

Angular

  • Для динамічної роботи з полями форми використовують FormArray або методи addControl() / removeControl() у FormGroup.
  • Це дозволяє створювати або видаляти поля на льоту - наприклад, динамічні списки чи масиви інпутів.

Приклад із FormArray:

form = new FormGroup({
  users: new FormArray<FormControl<string>>([])
});

get users() {
  return this.form.get('users') as FormArray;
}

addUser() {
  this.users.push(new FormControl('', Validators.required));
}

removeUser(index: number) {
  this.users.removeAt(index);
}

HTML:

<form [formGroup]="form">
  <div formArrayName="users">
    <div *ngFor="let user of users.controls; let i = index">
      <input [formControlName]="i" />
      <button type="button" (click)="removeUser(i)">Remove</button>
    </div>
  </div>
  <button type="button" (click)="addUser()">Add User</button>
</form>

Коротко:

  • Використовуй FormArray для списків контролів.
  • Використовуй addControl() / removeControl() у FormGroup для динамічних окремих полів.
40. Що таке FormGroup у Angular і як він працює?

Angular

  • FormGroup - це об’єкт, який об’єднує кілька FormControl або навіть інших FormGroup у єдину структуру. Він дозволяє керувати станом, значеннями та валідацією всієї групи як одного цілого.

Ключові моменти:

  • FormGroup зберігає набір контролів у вигляді об’єкта.

  • Дозволяє отримати стан (valid, dirty, touched) або значення (value) всієї групи.

  • Може мати групову валідацію (на рівні всієї форми).

Приклад:

form = new FormGroup({ user: new FormGroup({ name: new FormControl('',
Validators.required), email: new FormControl('', Validators.email) }) });

HTML:

<form [formGroup]="form">
  <div formGroupName="user">
    <input formControlName="name" />
    <input formControlName="email" />
  </div>
</form>

Коротко:

  • FormGroup = контейнер для контролів → дає змогу керувати групою полів як єдиним об’єктом (для валідації, оновлення, сабміту).
41. Як створити власні (custom) валідатори у формах Angular?

Angular

Кастомний валідатор - це функція, яка приймає FormControl або AbstractControl і повертає об’єкт помилки { [key: string]: any } або null, якщо помилок немає. Її можна використовувати в Reactive Forms або Template-driven.

Синхронний валідатор (приклад):

import { AbstractControl, ValidationErrors } from '@angular/forms';

export function forbiddenWordValidator(control: AbstractControl):
ValidationErrors | null { const forbidden = control.value?.toLowerCase() ===
'admin'; return forbidden ? { forbiddenWord: true } : null; }

Використання:

form = new FormGroup({ username: new FormControl('', [forbiddenWordValidator])
});

Асинхронний валідатор (приклад):

export function uniqueEmailValidator(service: UserService) {
  return (control: AbstractControl) => {
    return service
      .checkEmail(control.value)
      .pipe(map(isTaken => (isTaken ? { emailTaken: true } : null)));
  };
}

Коротко:

  • Кастомний валідатор - це функція, що повертає { errorKey: true } або null.
  • Може бути синхронним або асинхронним (через Observable).
  • Підходить для складної бізнес-логіки, якої немає серед стандартних Validators.
42. Поясни, як використовувати formArrayName для роботи з полями форми типу масиву в Angular.

Angular

  • formArrayName використовується в шаблоні для прив’язки до FormArray усередині Reactive Forms. Це дозволяє відображати та керувати динамічними наборами полів (наприклад, списком телефонів, тегів чи користувачів).

Приклад:

form = new FormGroup({
  phones: new FormArray<FormControl<string>>([
    new FormControl('', Validators.required)
  ])
});

get phones() {
  return this.form.get('phones') as FormArray;
}

addPhone() {
  this.phones.push(new FormControl('', Validators.required));
}

removePhone(index: number) {
  this.phones.removeAt(index);
}

HTML:

<form [formGroup]="form">
  <div formArrayName="phones">
    <div *ngFor="let phone of phones.controls; let i = index">
      <input [formControlName]="i" placeholder="Phone number" />
      <button type="button" (click)="removePhone(i)">Remove</button>
    </div>
  </div>

  <button type="button" (click)="addPhone()">Add Phone</button>
</form>

Коротко:

  • formArrayName - це директива для доступу до FormArray у шаблоні.
  • Кожен елемент масиву - окремий FormControl або FormGroup.
  • Використовується для динамічних форм, де кількість полів може змінюватися.
43. Як відправити дані форми з Angular-додатку на бекенд-сервіс?

Angular

  • У Angular форма зазвичай відправляється через сервіс, який використовує HttpClient для HTTP-запиту (POST, PUT тощо). Після сабміту зчитують form.value, перевіряють form.valid і викликають метод сервісу.

Приклад:

// user.service.ts
@Injectable({ providedIn: 'root' })
export class UserService {
  constructor(private http: HttpClient) {}

  submitUser(data: any) {
    return this.http.post('/api/users', data);
  }
}
// component.ts
form = new FormGroup({
  name: new FormControl('', Validators.required),
  email: new FormControl('', Validators.email)
});

constructor(private userService: UserService) {}

onSubmit() {
  if (this.form.valid) {
    this.userService.submitUser(this.form.value).subscribe({
      next: () => console.log('User saved!'),
      error: err => console.error('Error:', err)
    });
  }
}

HTML:

<form [formGroup]="form" (ngSubmit)="onSubmit()">
  <input formControlName="name" />
  <input formControlName="email" />
  <button type="submit">Save</button>
</form>

Коротко:

  • Отримуєш form.value.
  • Перевіряєш form.valid.
  • Відправляєш через HttpClient (звичайно через сервіс).
  • Обробляєш відповідь у subscribe().
44. Що таке виявлення змін (change detection) і як його реалізує Angular?

Angular

Виявлення змін (change detection) - це процес, за допомогою якого Angular визначає, що дані в компоненті змінились, і оновлює відповідні частини UI.

Як Angular це реалізує:

  • У сучасному Angular механізм базується на Signals - Angular відслідковує залежності між сигналами та шаблоном і оновлює тільки ті фрагменти DOM, які справді змінились (fine-grained reactivity, без глобального циклу).

  • Без Signals Angular використовує Zone.js, який перехоплює async-події і запускає перевірку всього дерева компонентів.

  • Для ручного контролю можливе використання ChangeDetectorRef.

Коротко:

Angular 20+ оновлює UI точково через Signals, а старий підхід (Zone.js + глобальна перевірка) використовується лише для зворотної сумісності.

45. Які основні способи оптимізації продуктивності Angular-застосунку?

Angular

  1. Використання Signals

Fine-grained reactivity → оновлюється тільки та частина DOM, яка залежить від сигналу.

  1. Standalone Components

Менший бандл, швидший старт, немає модульних оверхедів.

  1. Lazy loading та route-level code splitting

Завантажувати лише той код, який потрібен на даному маршруті.

  1. OnPush (для legacy компонентів без сигналів)

Зменшує кількість викликів change detection у старих компонентах.

  1. trackBy у ngFor

Запобігає перерендеру списків:

<li *ngFor="let item of items; trackBy: trackById"></li>
  1. Оптимізація RxJS

takeUntil, shareReplay, уникання непотрібних сабскрипцій.

  1. Async Pipe замість manual subscribe

Запобігає memory leaks і зайвим CD-циклами.

  1. Оптимізація шаблону

Мінімізувати важкі обчислення у template (винести в getters або signals).

  1. Preloading strategies

Оптимізує навігацію між маршрутами (наприклад, PreloadAllModules або custom).

  1. Build-level оптимізації

ng build --configuration production

minification, treeshaking, локальні i18n-файли

image optimization (WebP/AVIF)

46. Що таке зони (Zones) в Angular і яку роль вони відіграють?

Angular

Зони (Zone.js) - це механізм, який перехоплює всі асинхронні операції (події, таймери, проміси) і автоматично запускає change detection після їх виконання.

Навіщо Angular використовує зони:

Щоб не писати вручну, коли саме оновлювати UI.

Будь-який async виклик → Angular знає, що могли змінитися дані → оновлює вʼю.

Як це працює:

Zone.js патчить setTimeout, XHR, addEventListener тощо.

Після завершення async-дії зона викликає Angular change detection.

У сучасному Angular 16–20+:

Зони більше не потрібні для реактивного рендерингу (Signals).

Є режим Noop Zone / Zoneless, де Angular оновлює UI точково без глобального CD.

Коротко:

Zones - старий механізм для автозапуску change detection. У нових версіях Angular його замінює сигнал-базована реактивність.

47. Як у Angular налаштувати SSR за допомогою Angular Universal

Angular

  1. Увімкнення SSR
ng add @angular/ssr

Автоматично створюється сервер, SSR bootstrap і hydration.

  1. Bootstrap

Browser

bootstrapApplication(AppComponent, appConfig);

Server

export default () =>
  bootstrapApplication(AppComponent, appConfig);
  1. Hydration
provideClientHydration()

Angular підхоплює HTML, а не рендерить заново.

  1. Сервер (Node / Express)
renderApplication(bootstrap, { url, document })
  1. SSR-safe код
isPlatformBrowser(PLATFORM_ID)

без window, document напряму

  1. Дані
  • API викликаємо на сервері

  • Передаємо в браузер через TransferState

  • Signals працюють з SSR без проблем

  1. Коли використовувати

SEO, швидкий FCP

  1. Коли не використовувати

Адмінки, real-time dashboards

48. У чому різниця між Ahead-of-Time (AOT) та Just-in-Time (JIT) компіляцією в Angular і коли використовується кожна з них?

Angular

AOT (Ahead-of-Time)

  • Компіляція під час білду

  • Angular-шаблони → JS до запуску в браузері

  • Швидший старт

  • Кращий performance

  • Менший бандл

  • Ранні compile-time помилки

  • Безпека (немає runtime compiler)

Default у production

JIT (Just-in-Time)

  • Компіляція в браузері під час виконання

  • Потрібен Angular compiler у runtime

  • Повільніший старт

  • Більший бандл

  • Зручно для dev (швидкий rebuild)

Використовується в dev-режимі

49. Опишіть декоратори, доступні в Angular.

Angular

Angular використовує TypeScript-декоратори для опису метаданих компонентів, директив, сервісів та DI.

  1. Класові декоратори

@Component

Описує UI-компонент.

@Component({ selector: 'app-user', standalone: true, template: `{{ name }}` })
export class UserComponent { name = 'Viktor'; }

@Directive

Створює кастомну директиву (attribute або structural).

@Directive({ selector: '[appHighlight]' }) export class HighlightDirective {}

@Pipe

Створює pipe для трансформації даних у шаблонах.

@Pipe({ name: 'uppercase' }) export class UppercasePipe { transform(value:
string) { return value.toUpperCase(); } }

@Injectable

Позначає клас як сервіс для DI.

@Injectable({ providedIn: 'root' }) export class UserService {}
  1. Property decorators (взаємодія з шаблоном)

@Input

Передача даних у компонент.

@Input() title!: string;

@Output

Передача подій з компонента.

@Output() saved = new EventEmitter<void>();

@HostBinding

Байндінг до властивостей host-елемента.

@HostBinding('class.active') isActive = true;

@HostListener

Підписка на події host-елемента.

@HostListener('click') onClick() {}
  1. Dependency Injection decorators

@Inject

Явна інʼєкція залежності.

constructor(@Inject(API_URL) private apiUrl: string) {}

@Optional

Залежність може бути відсутня.

constructor(@Optional() private logger?: LoggerService) {}

@Self, @SkipSelf

Контроль області пошуку залежностей.

constructor(@Self() private control: NgControl) {}
  1. View / Content decorators

@ViewChild / @ViewChildren

Доступ до елементів власного шаблону.

@ViewChild('input') input!: ElementRef;

@ContentChild / @ContentChildren

Доступ до проєктованого контенту (ng-content).

@ContentChild(TemplateRef) tpl!: TemplateRef<any>;
  1. Стан у Angular 20+
  • Декоратори все ще підтримуються

  • Але часто замінюються:

    • inject() замість constructor DI

    • Signals замість @Input + ngOnChanges

  • Standalone API не скасовує декоратори, лише спрощує архітектуру

50. Як реалізувати анімаційні переходи в Angular-додатку?

Angular

Angular має вбудовану систему анімацій через @angular/animations. У Angular 20+ використовую provideAnimations() у конфігурації:

// app.config.ts
import { provideAnimations } from '@angular/platform-browser/animations';

export const appConfig: ApplicationConfig = {
  providers: [provideAnimations()]
};
  1. Анімація станів компонента
typescriptimport { trigger, state, style, transition, animate } from '@angular/animations';

@Component({
  template: `<div [@openClose]="isOpen()">Content</div>`,
  animations: [
    trigger('openClose', [
      state('true', style({ height: '200px', opacity: 1 })),
      state('false', style({ height: '0px', opacity: 0 })),
      transition('false <=> true', animate('300ms ease-in-out'))
    ])
  ]
})
export class MyComponent {
  isOpen = signal(false);
}
  1. Анімація роутів
// app.component.ts
@Component({
  template: `
    <div [@routeAnimations]="outlet.activatedRouteData['animation']">
      <router-outlet #outlet="outlet"></router-outlet>
    </div>
  `,
  animations: [
    trigger('routeAnimations', [
      transition('* <=> *', [
        query(':enter', [style({ opacity: 0 })], { optional: true }),
        query(':leave', [animate('200ms', style({ opacity: 0 }))], { optional: true }),
        query(':enter', [animate('300ms', style({ opacity: 1 }))], { optional: true })
      ])
    ])
  ]
})
  1. Анімація списків (stagger)
animations: [
  trigger('listAnimation', [
    transition('* => *', [
      query(':enter', [
        style({ opacity: 0, transform: 'translateY(-20px)' }),
        stagger(100, [
          animate('300ms', style({ opacity: 1, transform: 'translateY(0)' }))
        ])
      ], { optional: true })
    ])
  ])
]

Best Practices

  • Використовую transform та opacity для GPU-acceleration
  • :enter / :leave для появи/зникнення елементів
  • Створюю reusable анімації через animation() та useAnimation()
  • Відстежую події: (@trigger.done)="onAnimationDone($event)"
51. Як створюються власні директиви в Angular?

Angular

  1. Типи директив
  • Attribute directive - змінює поведінку або вигляд елемента приклад: highlight, tooltip

  • Structural directive - змінює структуру DOM приклад: *ngIf, *ngFor

  1. Attribute directive

Приклад: директива підсвічування

import { Directive, ElementRef, Input, effect, signal } from '@angular/core';

@Directive({
  selector: '[appHighlight]',
  standalone: true,
})
export class HighlightDirective {
  color = signal('yellow');

  constructor(private el: ElementRef) {
    effect(() => {
      this.el.nativeElement.style.backgroundColor = this.color();
    });
  }

  @Input()
  set appHighlight(value: string) {
    this.color.set(value);
  }
}

Використання

<p appHighlight="lightblue">Highlighted text</p>
  1. Structural directive

Приклад: кастомний *appIf

import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[appIf]',
  standalone: true,
})
export class AppIfDirective {
  constructor(
    private tpl: TemplateRef<unknown>,
    private vcr: ViewContainerRef
  ) {}

  @Input()
  set appIf(condition: boolean) {
    this.vcr.clear();
    if (condition) {
      this.vcr.createEmbeddedView(this.tpl);
    }
  }
}

Використання

<div *appIf="isVisible">Visible content</div>
  1. Best practices
  • Використовуйте standalone директиви

  • Для реактивності - signals + effect

  • Уникайте прямої роботи з DOM (краще Renderer2, якщо потрібно)

  • Мінімізуйте side-effects у constructor

  • Structural директиви завжди працюють через TemplateRef + ViewContainerRef

Коротко

Власні директиви створюються через @Directive, бувають attribute та structural і в Angular 20+ зазвичай є standalone з реактивністю на signals.

52. Чи можете ви пояснити використання директив ngClass та ngStyle?

Angular

Використання директив ngClass та ngStyle в Angular

ngClass

Директива ngClass використовується для динамічного додавання або видалення CSS-класів на елементі.

Основні форми використання

  1. Обʼєкт (найпоширеніше)
<div [ngClass]="{ active: isActive, disabled: isDisabled }"></div>
  1. Масив
<div [ngClass]="['card', isDark ? 'dark' : 'light']"></div>
  1. Рядок
<div [ngClass]="dynamicClass"></div>

Best practices

  • Використовуйте для умовної стилізації

  • Працює ефективно з ChangeDetectionStrategy.OnPush

  • Добре поєднується з signals

isActive = signal(true);

ngStyle

Директива ngStyle використовується для динамічного задання inline-стилів.

Приклад

<div [ngStyle]="{ color: textColor, fontSize: fontSize + 'px' }"></div>
textColor = 'red';
fontSize = 16;

Best practices

  • Використовуйте лише коли стилі не можна описати класами

  • Уникайте великої кількості inline-стилів (performance + maintainability)

Angular 20+ рекомендації

  • Віддавайте перевагу ngClass

  • Для складної логіки - computed signals

  • Для дизайн-систем - класи + CSS variables

Коротке резюме

  • ngClass - для керування CSS-класами,
  • ngStyle - для динамічних inline-стилів.
53. Як ви взаємодієте з DOM безпосередньо за допомогою директив?

Angular

Взаємодія з DOM за допомогою директив в Angular

Основні способи

  1. ElementRef (обмежено)

Дає доступ до нативного DOM-елемента.

constructor(private el: ElementRef) {
  this.el.nativeElement.focus();
}

Недолік: прямий доступ до DOM Не рекомендовано для SSR та безпеки

  1. Renderer2 (рекомендовано)

Абстракція над DOM - безпечна та SSR-friendly.

constructor(
  private el: ElementRef,
  private renderer: Renderer2
) {}

ngOnInit() {
  this.renderer.setStyle(
    this.el.nativeElement,
    'background-color',
    'yellow'
  );
}
  • Працює з SSR
  • Безпечний (XSS)
  • Кросплатформений
  1. @HostBinding Біндінг до властивостей host-елемента.
@HostBinding('class.active') isActive = true;
  • Чисто
  • Без прямого DOM-доступу
  1. @HostListener

Підписка на події host-елемента.

@HostListener('mouseenter')
onHover() {
  this.isActive = true;
}

Angular 20+ підхід (best practice)

  • Уникати nativeElement напряму

  • Використовувати Renderer2

  • Для стилів і класів - @HostBinding

  • Для подій - @HostListener

  • Для реактивності - signals + effect

  • Перевіряти платформу (isPlatformBrowser) при роботі з DOM API

Коротко

У Angular взаємодія з DOM у директивах має відбуватись через Renderer2 або host-декоратори, а не через прямий доступ до nativeElement.

54. Коли слід використовувати Renderer2 і які його переваги?

Angular

Коли слід використовувати Renderer2 і які його переваги

Коли використовувати Renderer2

Використовуйте Renderer2, коли потрібно:

  • Динамічно змінювати стилі, класи, атрибути
  • Додавати або видаляти DOM-елементи
  • Працювати з подіями зсередини директив
  • Забезпечити SSR-сумісність
  • Уникнути XSS-ризиків
  • Писати кросплатформений код (browser / server / web workers)

Приклад використання

import { Directive, ElementRef, Renderer2 } from '@angular/core';

@Directive({
  selector: '[appHighlight]',
  standalone: true,
})
export class HighlightDirective {
  constructor(
    private el: ElementRef,
    private renderer: Renderer2
  ) {
    this.renderer.setStyle(
      this.el.nativeElement,
      'background-color',
      'yellow'
    );
  }
}

Переваги Renderer2

  1. Безпека
  • Захищає від XSS
  • Не дозволяє небезпечні DOM-операції напряму
  1. SSR-friendly
  • Працює коректно при Server-Side Rendering
  • Не ламається через відсутність window / document
  1. Абстракція над DOM
  • Angular вирішує як саме застосувати зміни
  • Підтримує різні платформи
  1. Краща підтримка Angular lifecycle
  • Інтегрується з change detection
  • Менше побічних ефектів

Коли НЕ варто використовувати Renderer2

  • Для простого керування класами → краще ngClass
  • Для обробки подій → краще @HostListener
  • Для стилів → @HostBinding
  • Для читання значень (read-only) → допустимо ElementRef

Angular 20+ рекомендації

  • Не використовувати nativeElement напряму
  • Renderer2 - стандарт для директив
  • Поєднувати з signals для реактивності
  • Перевіряти платформу при складних DOM-операціях

Коротко

Renderer2 - це безпечний, SSR-сумісний та кросплатформений спосіб взаємодії з DOM, який слід використовувати замість прямого доступу до nativeElement.

55. Як створити власний канал в Angular?

Angular

Як створити власний Pipe (канал) в Angular

  1. Створення pipe

Приклад: простий pipe для форматування імені

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'capitalize',
  standalone: true,
})
export class CapitalizePipe implements PipeTransform {
  transform(value: string): string {
    if (!value) return '';
    return value[0].toUpperCase() + value.slice(1);
  }
}
  1. Використання в шаблоні
<p>{{ 'angular' | capitalize }}</p>
  1. Pure vs Impure pipes

Pure pipe (за замовчуванням)

  • Викликається лише при зміні input

  • Краща продуктивність

@Pipe({ name: 'myPipe', pure: true })

Impure pipe

  • Викликається на кожен change detection

  • Використовувати обережно

@Pipe({ name: 'myPipe', pure: false })
  1. Pipe з параметрами
@Pipe({ name: 'truncate', standalone: true })
export class TruncatePipe implements PipeTransform {
  transform(value: string, limit = 10): string {
    return value.length > limit ? value.slice(0, limit) + '…' : value;
  }
}
<p>{{ text | truncate:20 }}</p>
  1. Best practices (Angular 20+)
  • Використовуйте standalone pipes

  • Тримайте pipes pure

  • Без side-effects

  • Не використовуйте pipes для складної бізнес-логіки

  • Для реактивних сценаріїв - signals або computed values

Коротко

Pipe в Angular створюється через @Pipe, реалізує PipeTransform і використовується для декларативної трансформації даних у шаблоні.

56. Опишіть чисті та нечисті канали.

Angular

Чисті (Pure) та нечисті (Impure) канали в Angular

Чисті канали (Pure Pipes)

Характеристики

  • Викликаються лише тоді, коли змінюється посилання на input
  • Значення кешується Angular
  • Висока продуктивність
  • Повністю детерміновані (без side-effects)
@Pipe({
  name: 'uppercase',
  standalone: true,
  pure: true, // default
})
export class UppercasePipe {}

Приклад використання

<p>{{ name | uppercase }}</p>

Коли використовувати

  • Форматування рядків

  • Обчислення на основі immutable-даних

  • 99% кейсів

Нечисті канали (Impure Pipes)

Характеристики

  • Викликаються на кожен цикл change detection
  • Не кешуються
  • Значно гірша продуктивність
  • Можуть мати side-effects (небажано)
Копіювати код
@Pipe({
  name: 'timeAgo',
  standalone: true,
  pure: false,
})
export class TimeAgoPipe {}

Приклад використання

<p>{{ timestamp | timeAgo }}</p>

Angular 20+ рекомендації

  • Завжди починайте з pure pipe

  • Уникайте impure pipes

  • Для реактивних сценаріїв:

    • Signals (computed)

    • RxJS + async

  • Impure pipe - останній варіант

Коротко

Pure pipes - швидкі та безпечні, Impure pipes - повільні й використовуються лише у виняткових випадках.

57. Що таке асинхронний канал і як він використовується?

Angular

Асинхронний канал (AsyncPipe) в Angular

Що таке async pipe

async - це вбудований Angular pipe, який:

  • підписується на Observable або Promise
  • автоматично оновлює шаблон при нових значеннях
  • сам відписується при знищенні компонента

Приклад з Observable

users$ = this.userService.getUsers();
<ul>
  <li *ngFor="let user of users$ | async">
    {{ user.name }}
  </li>
</ul>

Приклад з Promise

dataPromise = fetchData();
<p>{{ dataPromise | async }}</p>

Як працює під капотом

  • Підписується на джерело даних
  • Тригерить change detection при нових значеннях
  • Відписується автоматично при destroy компонента

Усунення memory leaks без ngOnDestroy

Переваги async pipe

  • Менше коду
  • Немає ручних subscribe / unsubscribe
  • Краще читається шаблон
  • Ідеально працює з OnPush
  • SSR та signals-friendly

async pipe + signals (Angular 20+)

import { toSignal } from
'@angular/core/rxjs-interop';

users = toSignal(this.userService.getUsers()); html Копіювати код
<li *ngFor="let user of users()">

Коли використовувати

  • Для роботи з HTTP-запитами
  • Для стрімів даних (RxJS)
  • Для реактивних UI-станів

Коли НЕ використовувати

  • Якщо значення потрібне лише в TS, а не в шаблоні
  • Для складної бізнес-логіки (краще в сервісах)

Коротко

async pipe - стандартний і безпечний спосіб роботи з асинхронними даними в шаблонах Angular без memory leaks.

58. Що таке NgRx і як він допомагає в управлінні станом?

Angular

Що таке NgRx і як він допомагає в управлінні станом

Що таке NgRx

NgRx - це бібліотека для state management в Angular, побудована на:

  • патерні Redux
  • RxJS
  • односпрямованому потоці даних (unidirectional data flow)

NgRx забезпечує єдине джерело правди (single source of truth) для стану застосунку.

Основні складові NgRx

  1. Store

Глобальний immutable-стан застосунку.

export interface AppState {
  users: User[];
}
  1. Actions

Описують що сталося.

export const loadUsers = createAction('[Users] Load');
  1. Reducers

Описують як змінюється стан.

export const usersReducer = createReducer( [],
on(loadUsersSuccess, (\_, { users }) => users) );
  1. Selectors

Ефективне отримання даних зі store.

export const selectUsers = createSelector( selectUsersState,
users => users );
  1. Effects

Робота з side-effects (HTTP, storage, navigation).

loadUsers$ = createEffect(() => this.actions$.pipe(
ofType(loadUsers), switchMap(() => this.api.getUsers()) ) );

Як NgRx допомагає керувати станом

  • Централізує стан
  • Робить змінюваність передбачуваною
  • Полегшує debugging (Redux DevTools)
  • Спрощує тестування
  • Добре масштабується для великих команд

Коли використовувати NgRx

  • Великі застосунки
  • Складний shared-state
  • Багато асинхронних side-effects
  • Потрібен time-travel debugging

Коли НЕ використовувати NgRx

  • Маленькі застосунки
  • Простий локальний стан
  • Overhead без потреби

Angular 20+ контекст

NgRx не замінює signals

  • Часто комбінується:

    • NgRx Store → глобальний стан
    • Signals → локальний UI-стан
  • Для простіших кейсів:

    • Signals
    • Component Store
    • Services + RxJS

Коротко

NgRx - це потужний, але важкий інструмент для управління станом, який варто використовувати лише тоді, коли складність застосунку цього вимагає.

59. Поясніть концепції дій, редукторів та ефектів у NgRx.

Angular

Дії, редуктори та ефекти в NgRx

  1. Actions (Дії)

Actions описують що сталося в застосунку.
Це прості обʼєкти з обовʼязковим полем type.

export const loadUsers = createAction('[Users] Load');
export const loadUsersSuccess = createAction(
  '[Users] Load Success',
  props<{ users: User[] }>()
);

Призначення

  • Тригерять зміну стану
  • Сигналізують про події (UI, API, router)
  1. Reducers (Редуктори)

Reducers - чисті функції, які визначають як змінюється стан у відповідь на action.

export const usersReducer = createReducer( initialState,
on(loadUsersSuccess, (state, { users }) => ({ ...state, users, })) );

Ключові правила

  • Без side-effects
  • Без мутацій
  • Повертають новий immutable-стан
  1. Effects (Ефекти)

Effects обробляють side-effects (HTTP, storage, navigation) і працюють поза reducer.

loadUsers$ = createEffect(() => this.actions$.pipe(
ofType(loadUsers), switchMap(() => this.api.getUsers().pipe( map(users =>
loadUsersSuccess({ users })) ) ) ) );

Призначення

  • Асинхронні операції
  • Взаємодія з зовнішніми API
  • Dispatch нових actions

Angular 20+ рекомендації

  • Reducers - максимально прості
  • Вся асинхронність - тільки в Effects
  • Signals можна використовувати поверх select
  • Для локального стану - ComponentStore

Коротко

Actions описують події, Reducers - змінюють стан, Effects - обробляють побічні ефекти, разом утворюючи передбачуваний односпрямований потік даних.

60. Як би ви зберігали стан програми після оновлення сторінки?

Angular

Основний підхід: Persist + Rehydrate

Зберігати стан у browser storage

  • localStorage - довготривалий стан
  • sessionStorage - лише на сесію
  • IndexedDB - великі обʼєми даних

Варіант 1: NgRx + Meta-Reducers (рекомендовано)

Persist + Rehydrate через ngrx-store-localstorage

import { localStorageSync } from 'ngrx-store-localstorage';

export const metaReducer: MetaReducer = reducer =>
  localStorageSync({
    keys: ['auth', 'settings'],
    rehydrate: true,
  })(reducer);
  • Автоматичне відновлення
  • Контроль, які slice зберігати
  • Production-ready

Варіант 2: NgRx вручну (simple case)

const savedState = JSON.parse(localStorage.getItem('appState') || '{}');
StoreModule.forRoot(reducers, {
  initialState: savedState,
});

Варіант 3: Без NgRx (Signals + Service)

@Injectable({ providedIn: 'root' })
export class AppStateService {
  theme = signal(
    localStorage.getItem('theme') ?? 'light'
  );

  constructor() {
    effect(() => {
      localStorage.setItem('theme', this.theme());
    });
  }
}
  • Мінімальний оверхед
  • Підходить для невеликого стану

Що зберігати / не зберігати

Зберігати

  • Auth / refresh tokens
  • User preferences
  • Filters, feature state

Не зберігати

  • Derived / computed state
  • Тимчасовий UI-стан
  • Великі API-колекції

Angular 20+ best practices

  • Persist тільки потрібні slices
  • Не зберігати sensitive data без шифрування
  • Для SSR - використовувати isPlatformBrowser
  • Signals - для локального стану
  • NgRx - для глобального

Коротко

Я зберігаю стан через persisting у browser storage та rehydration при старті, використовуючи NgRx meta-reducers або signals + services залежно від складності застосунку.

61. Чи можете ви обговорити концепцію незмінності в управлінні станами?

Angular

Концепція незмінності (Immutability) в управлінні станами

Що таке незмінність

Незмінність означає, що стан не змінюється напряму.
Кожна зміна створює новий обʼєкт стану, а старий залишається незмінним.

// Мутація
state.count++;

// Незмінно
{ ...state, count: state.count + 1 }

Чому це важливо

  1. Передбачуваність
  • Один action → один новий стан
  • Без прихованих побічних ефектів
  1. Продуктивність
  • Angular використовує reference checks
  • Ефективна робота з OnPush та signals
  1. Debugging
  • Time-travel debugging (NgRx DevTools)
  • Легко відстежувати зміни стану
  1. Тестування
  • Reducers - чисті функції
  • Просте unit-тестування

Незмінність у NgRx

on(updateUser, (state, { user }) => ({
  ...state,
  user: { ...state.user, ...user }
}))

Заборонено:

state.user.name = user.name;

Angular 20+ контекст

  • Signals реагують на зміну посилань
  • computed() перевиконується лише при новому reference
  • Immutability = краща продуктивність UI

Типові помилки

  • Мутація вкладених обʼєктів
  • Використання .push() / .splice()
  • Зміни state поза reducer / сервісом

Коротко

Незмінність - основа надійного state management: вона забезпечує передбачуваність, продуктивність і зручне тестування.

62. Як тестувати компоненти Angular?

Angular

Основні типи тестування

  1. Unit-тести (основні)

Тестують ізольовану логіку компонента.

Інструменти:

  • TestBed
  • Jasmine / Jest
  • Karma (або Vite + Vitest)
beforeEach(() => {
  TestBed.configureTestingModule({
    imports: [MyComponent], // standalone
  });
});

it('should create component', () => {
  const fixture = TestBed.createComponent(MyComponent);
  expect(fixture.componentInstance).toBeTruthy();
});
  1. Тестування шаблону (DOM)

Перевірка рендерингу та binding’ів.

it('should render title', () => {
  const fixture = TestBed.createComponent(MyComponent);
  fixture.componentInstance.title = 'Hello';
  fixture.detectChanges();

  const el = fixture.nativeElement.querySelector('h1');
  expect(el.textContent).toContain('Hello');
});
  1. Тестування взаємодії (events)
it('should emit event on click', () => {
  spyOn(component.saved, 'emit');

  const button = fixture.nativeElement.querySelector('button');
  button.click();

  expect(component.saved.emit).toHaveBeenCalled();
});

Mock залежностей

Mock сервісів

providers: [
  { provide: UserService, useValue: mockUserService }
]

HttpClient

import { provideHttpClientTesting } from '@angular/common/http/testing';

providers: [provideHttpClientTesting()]

Signals у тестах (Angular 20+)

it('should update signal value', () => {
  component.count.set(1);
  expect(component.count()).toBe(1);
});

Що тестувати, а що ні

Тестувати

  • Бізнес-логіку компонента
  • Взаємодію з сервісами
  • Binding’и та events

Не тестувати

  • Внутрішню реалізацію Angular
  • CSS / стилі
  • Простий boilerplate

Best practices

  • Використовуйте standalone components у тестах
  • Мінімізуйте TestBed конфіг
  • Mock тільки зовнішні залежності
  • Один тест - одна відповідальність
  • Для UI-флоу - e2e (Cypress / Playwright)

Коротко

Компоненти Angular тестуються переважно unit-тестами через TestBed, з моками залежностей та перевіркою DOM і взаємодій; у Angular 20+ тести простіші завдяки standalone та signals.

63. Поясніть, що таке TestBed та його роль у тестуванні Angular.

Angular

Що таке TestBed

TestBed - це основний тестовий API Angular, який:

  • створює ізольоване тестове середовище
  • емулює Angular DI, change detection та lifecycle
  • дозволяє конфігурувати залежності так само, як у реальному застосунку

Основні можливості TestBed

  1. Конфігурація тестового модуля
TestBed.configureTestingModule({
  imports: [MyComponent], // standalone
  providers: [MyService],
});
  1. Створення компонента
const fixture = TestBed.createComponent(MyComponent);
const component = fixture.componentInstance;
  1. Керування change detection
fixture.detectChanges();
  1. Доступ до DI
const service = TestBed.inject(MyService);

TestBed у Angular 20+

  • Підтримує standalone components
  • Не потребує NgModule
  • Працює з signals
  • Сумісний з SSR і zoneless режимом
  • Менше boilerplate, ніж у старих версіях

Коли використовувати TestBed

Використовувати

  • Для тестування компонентів
  • Для інтеграційних unit-тестів
  • Коли потрібні DI та lifecycle

Не обовʼязково

  • Для простих pure-функцій
  • Для логіки без Angular-залежностей

Best practices

  • Мінімізуйте конфігурацію TestBed
  • Імпортуйте лише тестований standalone-компонент
  • Mock зовнішні залежності
  • Не тестуйте Angular internals

Коротко

TestBed - це тестовий інструмент Angular, який створює середовище, максимально наближене до реального застосунку, і є основою тестування компонентів та сервісів.

64. Як ви створюєте імітаційний імітаційний код сервісу Angular для цілей тестування?

Angular

Навіщо потрібні mock-сервіси

  • Ізолювати тест від реальних залежностей (HTTP, storage, API)
  • Зробити тести швидкими та детермінованими
  • Тестувати поведінку, а не реалізацію

Основні способи створення mock-сервісів

  1. Простий mock-обʼєкт (найчастіше)
const userServiceMock = {
  getUsers: () => of([{ id: 1, name: 'Test User' }]),
};
TestBed.configureTestingModule({
  imports: [MyComponent],
  providers: [
    { provide: UserService, useValue: userServiceMock },
  ],
});
  • Просто
  • Швидко
  • Ідеально для unit-тестів
  1. Mock-клас
class UserServiceMock {
  getUsers() {
    return of([]);
  }
}
providers: [
  { provide: UserService, useClass: UserServiceMock }
]
  • Краще для складної логіки
  • Більше boilerplate
  1. Spy-обʼєкти (Jasmine / Jest)

Jasmine

const userServiceSpy = jasmine.createSpyObj('UserService', ['getUsers']);
userServiceSpy.getUsers.and.returnValue(of([]));

Jest

const userServiceMock = {
  getUsers: jest.fn().mockReturnValue(of([])),
};
  • Перевірка викликів
  • Контроль поведінки
  1. HttpClient mock (для API)
import { provideHttpClientTesting } from '@angular/common/http/testing';

TestBed.configureTestingModule({
  providers: [provideHttpClientTesting()],
});
httpMock.expectOne('/api/users').flush([]);

Angular 20+ рекомендації

  • Mock через useValue - default вибір
  • Не використовуйте реальні HTTP-запити
  • Mock тільки зовнішні залежності
  • Один mock = один тестовий сценарій
  • Для signals - просто викликайте .set()

Типові помилки

  • Мокати приватні методи
  • Тестувати реалізацію замість поведінки
  • Підміняти весь Store замість slice

Коротко

Mock-сервіси в Angular створюються через useValue, useClass або spy-обʼєкти і дозволяють ізольовано та надійно тестувати компоненти й сервіси.

65. Чи можна виконувати наскрізне тестування в Angular?

Angular

Коротка відповідь

Так, Angular повністю підтримує E2E (end-to-end) тестування, але не має вбудованого інструмента - використовується зовнішній тест-раннер.

Рекомендовані інструменти

Playwright (рекомендовано)

  • Сучасний стандарт
  • Швидкий і стабільний
  • Працює з SSR та SPA
  • Підтримує multiple browsers
npm init playwright@latest
test('login flow', async ({ page }) => {
  await page.goto('/');
  await page.fill('#email', 'test@mail.com');
  await page.click('button[type=submit]');
  await expect(page).toHaveURL('/dashboard');
});

Cypress

  • Простий у використанні
  • Чудовий dev experience
  • Менш стабільний для складних SSR-сценаріїв
cy.visit('/');
cy.get('input').type('test@mail.com');
cy.contains('Submit').click();

Protractor

  • Deprecated
  • Не рекомендується у сучасних Angular-проєктах

Що тестує E2E

  • Реальні користувацькі флоу
  • Навігацію
  • Інтеграцію з бекендом
  • Авторизацію
  • SSR + hydration (якщо є)

Best practices

  • Мінімізувати кількість E2E-тестів
  • Не тестувати дрібну логіку (для цього unit)
  • Використовувати test IDs (data-testid)
  • Мокати бекенд або використовувати test environment
  • Запускати E2E у CI

Angular 20+ контекст

  • E2E працює з standalone та signals без проблем
  • SSR тестується через Playwright
  • Zoneless режим не впливає на E2E

Коротко

Angular не має власного E2E-фреймворку, але відмінно працює з Playwright і Cypress для повноцінного наскрізного тестування.

66. Які відмінності між Jasmine та Karma в контексті тестування Angular?

Angular

Коротко

  • Jasmine - це фреймворк для написання тестів
  • Karma - це тест-раннер, який запускає ці тести в браузерах

Вони доповнюють, а не замінюють одне одного.

Jasmine

Що це

BDD-тестовий фреймворк, який надає:

  • describe, it, beforeEach
  • expect, matchers
  • spies (spyOn)
describe('Counter', () => {
  it('should increment', () => {
    expect(1 + 1).toBe(2);
  });
});

Відповідає за

  • Синтаксис тестів
  • Assertions
  • Mock / Spy логіку

Karma

Що це

Test runner, який:

  • Запускає тести
  • Відкриває браузери (Chrome, Firefox, Headless)
  • Відслідковує файли та перезапускає тести
  • Репортує результати
ng test

Відповідає за

  • Середовище виконання
  • Інтеграцію з браузером
  • CI-запуск

Angular 20+ контекст

  • Jasmine + Karma - legacy default
  • Все частіше замінюються на:
    • Jest
    • Vitest (Vite)
  • Karma повільніший, але стабільний
  • Jasmine простий, але менш гнучкий за Jest

Best practices

  • Для нових проєктів:
    • Vitest / Jest
  • Для legacy Angular:
    • Jasmine + Karma - ок
  • Не змішувати відповідальності інструментів

Коротко

Jasmine пише тести, Karma запускає тести, разом вони утворюють класичний стек тестування Angular.

67. Які стратегії ви б використали для зменшення часу завантаження програми Angular?

Angular

  1. Lazy Loading (критично важливо)

Lazy routes

{
  path: 'admin',
  loadComponent: () =>
    import('./admin/admin.component').then(m => m.AdminComponent),
}
  • Менший initial bundle
  • Швидший старт
  1. Standalone + Tree Shaking
  • Використовувати standalone components
  • Імпортувати тільки необхідні залежності
@Component({ standalone: true, imports: [CommonModule], })
  1. Change Detection Optimization
  • ChangeDetectionStrategy.OnPush
  • Signals замість зайвого RxJS
changeDetection: ChangeDetectionStrategy.OnPush
  1. SSR + Hydration (якщо є SEO)
  • SSR для швидкого First Contentful Paint
  • Hydration для уникнення повторного рендеру
provideClientHydration()
  1. Code Splitting & Dynamic Imports
  • Динамічно завантажувати важкі бібліотеки
const chart = await import('chart.js');
  1. Оптимізація Assets
  • Lazy loading зображень
<img src="img.png" loading="lazy" />
  • Стиснення (gzip / brotli)
  • Мінімізація шрифтів
  1. Zoneless Angular (Angular 20+)
provideExperimentalZonelessChangeDetection()
  • Менше runtime overhead
  • Потрібна дисципліна в реактивності
  1. Preloading стратегія
withPreloading(PreloadAllModules)

Завантажує lazy-модулі після старту

  1. Видалення зайвого
  • Не імпортувати CommonModule без потреби
  • Не використовувати impure pipes
  • Мінімізувати глобальні стилі

Коротко

Найбільший ефект дають lazy loading, standalone + OnPush, SSR з hydration та code splitting; дрібні оптимізації мають сенс лише після цього.

68. Поясніть ліниве завантаження та як воно покращує продуктивність програми.

Angular

Lazy loading - це підхід, за якого частини застосунку завантажуються лише тоді, коли вони реально потрібні, а не під час старту.

Lazy loading роутів (standalone)

{
  path: 'dashboard',
  loadComponent: () =>
    import('./dashboard/dashboard.component')
      .then(m => m.DashboardComponent),
}

Як це покращує продуктивність

  1. Менший initial bundle
  • Менше JS на старті
  • Швидший First Load
  1. Швидший Time to Interactive (TTI)
  • Браузер швидше стає інтерактивним
  1. Краще використання мережі
  • Код завантажується on demand
  • Менше непотрібних запитів

Додаткові оптимізації

Preloading

Після старту застосунку Angular може підвантажити lazy-модулі у фоні.

withPreloading(PreloadAllModules)

Best practices

  • Lazy load feature areas, а не дрібні компоненти
  • Не lazy load critical UI
  • Поєднувати з OnPush
  • Використовувати standalone components
  • Lazy load важкі сторонні бібліотеки

Типові помилки

  • Lazy loading кожного компонента
  • Lazy loading root layout
  • Відсутність fallback UI (loading)

Коротко

Lazy loading зменшує розмір стартового бандлу, пришвидшує завантаження та покращує UX, завантажуючи код лише тоді, коли він потрібен.

69. Як би ви реалізували розділення коду в Angular для покращення продуктивності?

Angular

Code splitting - це розбиття JavaScript-коду на окремі чанки, які завантажуються за потреби, а не всі одразу при старті.

  1. Lazy loading маршрутів (основний інструмент)

Standalone components

{
  path: 'profile',
  loadComponent: () =>
    import('./profile/profile.component')
      .then(m => m.ProfileComponent),
}
  • Менший initial bundle
  • Швидший старт застосунку
  1. Lazy loading feature areas

Розділяйте застосунок по фічах, а не по дрібних компонентах.

{
  path: 'admin',
  loadChildren: () =>
    import('./admin/admin.routes')
      .then(m => m.ADMIN_ROUTES),
}
  1. Динамічні імпорти для важких бібліотек
async loadChart() {
  const { Chart } = await import('chart.js');
  new Chart(...);
}

Бібліотека не потрапляє в initial bundle

  1. Preloading (баланс між швидкістю і UX)
provideRouter(
  routes,
  withPreloading(PreloadAllModules)
);
  • Lazy модулі завантажуються після старту
  • Покращує UX без шкоди initial load
  1. Standalone + Tree Shaking
  • Використовуйте standalone components
  • Імпортуйте тільки необхідні залежності
@Component({
  standalone: true,
  imports: [CommonModule],
})

Best practices

  • Lazy load pages / feature areas
  • Не lazy load critical UI
  • Не дробіть код надто дрібно
  • Поєднувати з OnPush та signals
  • Вимірювати ефект через bundle analyzer

Типові помилки

  • Lazy loading кожного компонента
  • Lazy loading layout/root
  • Відсутність loading state

Коротко

Code splitting в Angular реалізується переважно через lazy loading маршрутів і dynamic imports, що суттєво зменшує initial bundle і покращує продуктивність.

70. Обговоріть використання опції trackBy в *ngFor для покращення продуктивності.

Angular

trackBy дозволяє Angular ідентифікувати елементи списку за унікальним ключем, а не за позицією в масиві.

Без trackBy Angular:

  • вважає, що всі елементи нові
  • перевидаляє та перерендерює весь DOM-список

З trackBy Angular:

  • оновлює тільки змінені елементи
  • зберігає існуючі DOM-ноди

Синтаксис

<li *ngFor="let user of users; trackBy: trackById">
  {{ user.name }}
</li>
trackById(index: number, user: User): number {
  return user.id;
}

Приклад проблеми без trackBy

this.users = [...this.users]; // новий reference
  • Без trackBy → весь список перерендериться
  • З trackBy → DOM залишиться стабільним

Коли trackBy критично важливий

  • Великі списки
  • Часті оновлення масиву
  • Реактивні дані (signals / RxJS)
  • OnPush change detection
  • Анімації в списках

Що використовувати як ключ

Добре

  • id
  • унікальний UUID
  • стабільний primary key

Погано

  • index
  • випадкові значення
  • значення, що можуть змінюватись

Angular 20+ контекст

  • Signals часто створюють нові references
  • trackBy + immutability = максимальна ефективність
  • Особливо важливо для zoneless Angular

Типові помилки

  • Не використовувати trackBy взагалі
  • Використовувати index
  • Повертати обʼєкт замість примітива

Коротко

trackBy дозволяє Angular оновлювати лише змінені елементи списку, значно зменшуючи кількість DOM-операцій і покращуючи продуктивність.

71. Як додати підтримку кількох мов у застосунок Angular?

Angular

Основні підходи

Вбудований Angular i18n (compile-time)

Підходить для SEO, SSR, статичних мов.

Кроки:

  1. Позначити тексти в шаблоні:
<h1 i18n="@@title">Hello</h1>
  1. Згенерувати файли перекладів:
ng extract-i18n
  1. Додати messages.xx.xlf (en, uk, pl, тощо)

  2. Зібрати для кожної мови:

ng build --localize

Плюси:

  • Максимальна продуктивність
  • SEO-friendly
  • Без runtime overhead

Мінуси:

  • Немає runtime-перемикання мови
  • Окремий build на кожну мову

ngx-translate (runtime i18n)

Підходить для динамічного перемикання мови.

npm install @ngx-translate/core @ngx-translate/http-loader
translate.use('uk');
<h1>{{ 'TITLE' | translate }}</h1>

Плюси:

  • Runtime switch
  • Один build
  • Зручно для SPA

Мінуси:

  • Гірше для SEO без SSR
  • Runtime overhead

Signals-based i18n (сучасний lightweight підхід)

language = signal<'en' | 'uk'>('en');

translations = { en: { title: 'Hello' }, uk: { title: 'Привіт' }, };

title = computed(() => translations[this.language()].title);
<h1>{{ title() }}</h1>

Плюси:

  • Мінімальний оверхед
  • Повний контроль
  • Ідеально для UI-стану

Мінуси:

  • Не підходить для великих словників

Best practices

  • Не змішувати підходи
  • Ключі перекладів мають бути стабільні
  • Lazy-load translation файлів
  • Для SSR - server-side locale

Коротко

У Angular багатомовність реалізується через Angular i18n (compile-time) або ngx-translate / signals (runtime) - вибір залежить від вимог до SEO та перемикання мов.

72. Опишіть процес реалізації локалізації Angular.

Angular

  1. Увімкнення i18n Angular i18n підтримується з коробки - додаткових бібліотек не потрібно.
ng add @angular/localize
  1. Позначення текстів у шаблонах
<h1 i18n="@@title">Hello</h1>
<p i18n>Welcome to our application</p>
  • i18n - маркер для перекладу
  • @@title - стабільний ключ (рекомендовано)
  1. Експорт текстів для перекладу
ng extract-i18n

Генерується файл messages.xlf (або .json, .arb)

  1. Створення файлів перекладу
messages.en.xlf
messages.uk.xlf
messages.pl.xlf

Кожен файл містить переклад для конкретної мови.

  1. Налаштування angular.json
"i18n": {
  "sourceLocale": "en",
  "locales": {
    "uk": "src/locale/messages.uk.xlf",
    "pl": "src/locale/messages.pl.xlf"
  }
}
  1. Збірка для різних мов
ng build --localize

Angular створює окремий build для кожної мови.

  1. Деплой та routing
  • Кожна мова має власний bundle
  • Часто використовується префікс у URL: /en, /uk, /pl
  • Для SSR - мова визначається на сервері

Angular 20+ особливості

  • i18n працює зі standalone components
  • Повністю сумісний з SSR + hydration
  • Немає runtime overhead
  • Максимальна продуктивність і SEO

Обмеження built-in i18n

  • Немає runtime-перемикання мови
  • Окремий build для кожної мови

Для runtime-перемикання використовують ngx-translate

Коротко

Локалізація в Angular реалізується через позначення текстів → експорт → переклад → multi-build, забезпечуючи високу продуктивність і SEO-сумісність.

73. Які найкращі практики безпеки для Angular-застосунків?

Angular

  1. Захист від XSS (Cross-Site Scripting)
  • Angular автоматично екранує дані в шаблонах
  • Не використовуйте innerHTML без потреби
  • Якщо потрібно - лише через DomSanitizer (обережно)
this.safeHtml = sanitizer.bypassSecurityTrustHtml(html);
  1. Уникати небезпечних API
<div [innerHTML]="html"></div>
<div>{{ text }}</div>
  1. HTTP безпека
  • Використовуйте HTTPS
  • Додавайте HTTP Interceptors для:
    • Authorization headers
    • CSRF-токенів
    • Centralized error handling
provideHttpClient(withInterceptors([authInterceptor]));
  1. Захист від CSRF
  • Використовуйте CSRF-токени (на боці бекенду)
  • Angular автоматично підтримує XSRF через cookies
HttpClientXsrfModule.withOptions({
  cookieName: 'XSRF-TOKEN',
  headerName: 'X-XSRF-TOKEN',
});
  1. Безпечне зберігання даних

Не зберігати sensitive data у localStorage

Краще:

  • HttpOnly cookies
  • Short-lived tokens
  • Мінімальний client-side state
  1. Route Guards і доступ

Захищайте приватні маршрути

canActivate: [AuthGuard]

Не довіряйте лише frontend - бекенд обовʼязковий

  1. Dependency Security

Регулярно оновлюйте Angular та бібліотеки

Використовуйте:

npm audit
  1. Build та Runtime безпека

Production build:

ng build --configuration production
  • Увімкнений AOT
  • Видалений debug-код
  • Без eval, Function, dynamic scripts
  1. Angular 20+ рекомендації
  • Standalone components → менша attack surface
  • Signals → менше небезпечних side-effects
  • Zoneless → менше глобальних патчів
  • SSR + hydration → безпечний initial render

Коротко

Безпека в Angular базується на вбудованому захисті від XSS, правильній роботі з HTTP, обмеженні доступу, безпечному зберіганні даних і регулярному оновленні залежностей.

74. Як запобігти міжсайтовому скриптингу (XSS) у застосунках Angular?

Angular

XSS - це атака, за якої зловмисник інʼєктує шкідливий JavaScript у сторінку, який виконується в браузері користувача.

  1. Вбудований захист Angular (основа)

Angular автоматично екранує всі дані, що рендеряться в шаблонах.

<!-- Безпечно -->
<div>{{ userInput }}</div>

HTML і JS не виконуються, а екрануються.

  1. Уникати небезпечних bindingʼів

Небезпечно

<div [innerHTML]="html"></div>

Безпечно

<div>{{ text }}</div>
  1. DomSanitizer - тільки за необхідності

Використовувати лише якщо довіряєте джерелу.

this.safeHtml =
  sanitizer.bypassSecurityTrustHtml(trustedHtml);

bypassSecurityTrust* відключає захист Angular

  1. Не виконувати динамічний код
eval(userInput);
new Function(userInput);

Погано

<a [href]="userInput">Link</a>

Добре

<a [attr.href]="safeUrl">Link</a>
  1. Безпечна робота з URL

Angular автоматично блокує:

  • javascript:
  • data: (у багатьох контекстах)
<img [src]="imageUrl" />

Angular перевіряє контекст (URL, HTML, style)

  1. HTTP + Backend захист
  • Завжди валідувати та очищати дані на бекенді
  • Використовувати Content Security Policy (CSP)
  • Не довіряти client-side валідації
  1. Angular 20+ best practices
  • Не використовувати innerHTML без потреби
  • Не зберігати HTML у state
  • Використовувати standalone components
  • Мінімізувати прямий DOM-доступ
  • Signals + template binding → безпечніше

Типові помилки

  • Використання bypassSecurityTrustHtml без розуміння
  • Рендеринг HTML з API
  • Зберігання user-generated HTML

Коротко

Angular за замовчуванням захищає від XSS, але розробник може сам створити вразливість, використовуючи innerHTML, eval або DomSanitizer без потреби.

75. Чи можна виконувати автентифікацію та авторизацію в застосунках Angular?

Angular

Коротка відповідь

Так. Angular повністю підтримує обидві концепції, але:

  • автентифікація зазвичай реалізується спільно з бекендом (JWT, OAuth)
  • авторизація - переважно на фронтенді через guards і policy-логіку
  1. Автентифікація (Authentication)

Це, перевірка хто користувач (login).

Типовий підхід

  • Login → бекенд
  • Отримання JWT / session
  • Збереження токена (HttpOnly cookie або memory)
login(credentials) {
  return this.http.post('/api/login', credentials);
}

Передача токена

Через HTTP Interceptor:

export const authInterceptor = (req, next) => {
  const token = authService.token();
  return next(
    req.clone({
      setHeaders: { Authorization: `Bearer ${token}` },
    })
  );
};
  1. Авторизація (Authorization)

Це, перевірка що користувач може робити.

Route Guards

export const authGuard: CanActivateFn = () => {
  return authService.isLoggedIn();
};
{
  path: 'admin',
  canActivate: [authGuard],
  loadComponent: () => import('./admin.component'),
}
  1. Ролі та права доступу
export const roleGuard: CanActivateFn = () => {
  return authService.hasRole('admin');
};
{ path: 'admin', canActivate: [roleGuard] }
  1. UI-рівень авторизації
<button *ngIf="isAdmin()">Delete</button>
isAdmin = computed(() => user()?.role === 'admin');
  1. Angular 20+ best practices
  • Не довіряти лише frontend-перевіркам
  • Backend завжди має фінальне слово
  • Guards - для routing
  • Interceptors - для токенів
  • Signals - для auth state
  • Не зберігати токени в localStorage (краще HttpOnly cookies)

Коротко

Angular дозволяє повноцінно реалізувати автентифікацію через бекенд і авторизацію через guards та UI-логіку, дотримуючись чіткої відповідальності між frontend і backend.

76. Чим TypeScript відрізняється від JavaScript і чому він є кращим в Angular?

Angular

JavaScript

  • Динамічно типізований
  • Типи перевіряються під час виконання
  • Гнучкий, але схильний до runtime-помилок
function sum(a, b) {
  return a + b;
}

sum(1, '2'); // "12" - помилка логіки

TypeScript

TypeScript = JavaScript + типи

  • Статична типізація (на етапі компіляції)
  • Раннє виявлення помилок
  • Краща читабельність і підтримуваність
function sum(a: number, b: number): number {
  return a + b;
}

// sum(1, '2'); ❌ compile-time error

Чому TypeScript кращий для Angular

  1. Архітектура та масштабування

Angular - enterprise-фреймворк, TypeScript:

  • робить код передбачуваним
  • зручний для великих команд
  1. Dependency Injection

Типи дозволяють Angular DI працювати надійно.

constructor(private userService: UserService) {}
  1. Декоратори та метадані

Angular активно використовує декоратори, які:

  • неможливі в чистому JS у такому вигляді
  • добре типізуються в TS
  1. Tooling та DX
  • Autocomplete
  • Навігація по коду
  • Safe refactoring
  • Strict mode (strict: true)
  1. Angular 20+ контекст
  • Signals
  • Standalone components
  • Typed forms
  • Typed HttpClient

Усе це максимально виграє від TypeScript

Коротко

TypeScript зменшує кількість помилок, покращує підтримуваність і масштабування коду, тому є природним і обґрунтованим вибором для Angular.

77. Які переваги використання інтерфейсів TypeScript у застосунках Angular?

Angular

Інтерфейси описують форму обʼєктів (structure typing) і використовуються лише на етапі компіляції.

interface User {
  id: number;
  name: string;
  email: string;
}

Основні переваги

  1. Статична типізація
  • Помилки виявляються до runtime
  • Менше багів у production
function printUser(user: User) {
  console.log(user.name);
}
  1. Контракти між шарами

Чіткі API між:

  • компонентами
  • сервісами
  • бекендом
getUser(): Observable<User> {}
  1. Краща читабельність і підтримка
  • Код самодокументований
  • Легше онбордити нових розробників
  1. IDE та DX
  • Autocomplete
  • Safe refactoring
  • Навігація по властивостях
  1. Інтеграція з Angular API

HttpClient

this.http.get<User[]>('/api/users');

Forms

form: FormGroup<UserForm>;

NgRx

interface AppState {
  users: User[];
}

Best practices в Angular

  • Інтерфейси - для data models
  • Не використовувати для runtime-логіки
  • Тримати окремо (models/, types/)
  • Використовувати разом зі strict mode

Коротко

Інтерфейси TypeScript роблять Angular-код типобезпечним, передбачуваним і масштабованим, що критично важливо для великих і довготривалих проєктів.

78. Чи можете ви пояснити використання декораторів у TypeScript, наводячи приклад в Angular?

Angular

Декоратори - це спеціальні функції TypeScript, які додають метадані або змінюють поведінку класів, методів, властивостей або параметрів під час компіляції.

Angular активно використовує декоратори для опису структури застосунку.

Основні типи декораторів у TypeScript

  • Class decorators
  • Property decorators
  • Method decorators
  • Parameter decorators

Приклад у Angular

  1. Class decorator - @Component
import { Component } from '@angular/core';

@Component({
  selector: 'app-user',
  standalone: true,
  template: `<h1>{{ name }}</h1>`,
})
export class UserComponent {
  name = 'Angular';
}

@Component додає метадані, за якими Angular розуміє:

  • що це компонент
  • як його рендерити
  • як він інтегрується в DI та change detection
  1. Property decorator - @Input
@Input() title!: string;

Дозволяє передавати дані в компонент ззовні

  1. Method decorator - @HostListener
@HostListener('click')
onClick() {
  console.log('Clicked');
}

Підписка на подію host-елемента

  1. Parameter decorator - @Inject
constructor(@Inject(API_URL) private apiUrl: string) {}

Явна інʼєкція залежності через Angular DI

Чому декоратори важливі для Angular

  • Формують метадані фреймворку
  • Дозволяють Angular працювати без reflection у runtime
  • Забезпечують:
    • Dependency Injection
    • Template binding
    • Change detection
  • Роблять код декларативним і читабельним

Angular 20+ контекст

  • Декоратори залишаються актуальними
  • Часто комбінуються з:
    • inject() (замість constructor DI)
    • Signals
  • Standalone API не скасовує декоратори

Коротко

Декоратори в TypeScript дозволяють Angular описувати компоненти, сервіси та DI декларативно; вони є фундаментом архітектури Angular і тісно інтегровані з TypeScript.

79. Як RxJS доповнює застосунки Angular?

Angular

RxJS - це бібліотека для реактивного програмування, яка працює з:

  • потоками даних (streams)
  • асинхронними подіями
  • операторами для трансформації та композиції

Angular використовує RxJS під капотом.

Ключові інтеграції RxJS в Angular

  1. HttpClient

Кожен HTTP-запит повертає Observable.

this.http.get<User[]>('/api/users')
  .pipe(map(users => users.filter(u => u.active)));
  1. Forms

Reactive Forms побудовані на RxJS.

this.form.valueChanges.subscribe(value => {
  console.log(value);
});
  1. Router

Router надає Observables для навігації.

this.router.events
  .pipe(filter(e => e instanceof NavigationEnd))
  .subscribe();
  1. State Management

NgRx повністю базується на RxJS.

  • Actions
  • Effects
  • Selectors

Що дає RxJS Angular-додаткам

  1. Управління асинхронністю
  • HTTP
  • WebSockets
  • User events
  • Timers
  1. Комбінування потоків
combineLatest([
  this.user$,
  this.settings$,
]).subscribe();
  1. Контроль життєвого циклу
this.stream$
  .pipe(takeUntilDestroyed())
  .subscribe();

RxJS + Angular 20+

  • RxJS все ще важливий
  • Але:
    • Signals - для локального UI-стану
    • RxJS - для async streams та side-effects
  • toSignal() / toObservable() для інтеграції
users = toSignal(this.users$);

Best practices

  • Не підписуватись вручну в шаблонах → async pipe
  • Не зловживати subscribe() в компонентах
  • Виносити RxJS-логіку в сервіси
  • Signals для синхронного стану

Коротко

RxJS є фундаментом асинхронності в Angular і доповнює його можливості для роботи з потоками даних, тоді як signals спрощують локальний UI-стан.

80. Поясніть призначення Subjects у RxJS та як вони використовуються в Angular.

Angular

Subject - це спеціальний тип Observable, який:

  • є одночасно Observable і Observer
  • дозволяє емітити значення вручну
  • підтримує мультикаст (один еміс → багато підписників)
const subject = new Subject<number>();

subject.subscribe(v => console.log(v));
subject.next(1);

Основні типи Subjects

  1. Subject
  • Не зберігає значення
  • Нові підписники не отримують попередні емісії
const s = new Subject<number>();
  1. BehaviorSubject (найпопулярніший)
  • Має початкове значення
  • Новий підписник одразу отримує останнє значення
const user$ = new BehaviorSubject<User | null>(null);
  1. ReplaySubject

Реплеїть N останніх значень

const logs$ = new ReplaySubject<string>(3);
  1. AsyncSubject
  • Віддає останнє значення після complete()
  • Рідко використовується

Як використовуються в Angular

Service як data source (поширений патерн)

@Injectable({ providedIn: 'root' })
export class AuthService {
  private userSubject = new BehaviorSubject<User | null>(null);
  user$ = this.userSubject.asObservable();

  setUser(user: User) {
    this.userSubject.next(user);
  }
}
<span *ngIf="auth.user$ | async as user">
  {{ user.name }}
</span>

Subjects vs Signals (Angular 20+)

  • Subjects - для async streams, events, side-effects
  • Signals - для локального синхронного UI-стану

Інтероп:

user = toSignal(this.user$);

Best practices

  • Не експортуйте Subject напряму → використовуйте asObservable()
  • Для state - BehaviorSubject
  • Не зловживати Subjects для простого UI-стану
  • Виносьте Subjects у сервіси
  • В шаблонах - async pipe

Типові помилки

  • Використання Subject замість BehaviorSubject для state
  • Ручні subscribe() без відписки
  • Змішування state і events в одному Subject

Коротко

Subjects дозволяють вручну керувати потоками даних і мультикастити значення; в Angular їх застосовують переважно в сервісах для async-подій та shared-state, тоді як signals краще підходять для локального UI-стану.

81. Які поширені оператори RxJS та як їх використовувати в Angular?

Angular

  1. Оператори трансформації

map

Перетворює значення потоку.

this.http.get<User[]>('/api/users')
  .pipe(map(users => users.filter(u => u.active)));

switchMap

Перемикається на новий Observable, скасовуючи попередній (ідеально для HTTP + UI events).

this.search$
  .pipe(
    switchMap(term => this.api.search(term))
  );

mergeMap

Паралельні запити, без скасування попередніх.

mergeMap(id => this.api.loadById(id))

concatMap

Черга запитів, виконує послідовно.

concatMap(task => this.api.run(task))
  1. Оператори фільтрації

filter

filter(user => user.isAdmin)

take, takeUntil

Обмеження кількості емісій / контроль lifecycle.

this.stream$
  .pipe(takeUntilDestroyed())
  .subscribe();
  1. Комбінування потоків

combineLatest

combineLatest([this.user$, this.settings$])

withLatestFrom

click$
  .pipe(withLatestFrom(this.user$))
  1. Error handling

catchError

catchError(() => of([]))
  1. Utility-оператори

tap

Side-effects (логування, debug).

tap(value => console.log(value))

debounceTime

Часто для input / search.

debounceTime(300)

Як використовуються в Angular

  • HttpClient → map, switchMap, catchError
  • Forms → valueChanges.pipe(debounceTime)
  • Router → filter, map
  • NgRx Effects → switchMap, mergeMap, concatMap

Angular 20+ рекомендації

  • RxJS - для асинхронних потоків
  • Signals - для локального UI-стану
  • У шаблонах - async pipe
  • Мінімізувати ручні subscribe()

Коротко

RxJS-оператори дозволяють трансформувати, комбінувати та контролювати асинхронні потоки в Angular; найважливіші - map, switchMap, filter, combineLatest, catchError.

82. Які є найкращі практики для структурування великої програми Angular?

Angular

  1. Feature-based структура (ключова)
  • Не за типами (components/, services/)
  • За фічами (domains)
src/app/
 ├─ auth/
 │   ├─ auth.routes.ts
 │   ├─ auth.component.ts
 │   └─ auth.service.ts
 ├─ dashboard/
 ├─ shared/
 └─ core/

Кожна фіча - ізольована та самодостатня

  1. Standalone-first підхід (Angular 20+)
  • NgModules
  • Standalone components, directives, pipes
@Component({
  standalone: true,
  imports: [],
})

Краще tree-shaking і простіша архітектура

  1. Lazy Loading фіч
{
  path: 'admin',
  loadChildren: () =>
    import('./admin/admin.routes')
      .then(m => m.ADMIN_ROUTES),
}
  • Менший initial bundle
  • Краще масштабування
  1. Core vs Shared

core/

  • Singleton сервіси
  • Auth, interceptors, guards
  • App-level providers

shared/

  • UI components
  • Pipes, directives
  • Без бізнес-логіки
  1. Чіткий поділ відповідальностей
  • Компоненти → UI + orchestration
  • Сервіси → бізнес-логіка
  • Store / signals → стан

Жодної складної логіки в шаблонах

  1. Управління станом
  • Signals → локальний UI-стан
  • NgRx / ComponentStore → глобальний або shared-стан
  • Не зберігати derived state
  1. Узгоджені конвенції
  • Naming conventions
  • Folder structure
  • Lint rules
  • Strict TypeScript
"strict": true
  1. Dependency Direction Rule
feature → shared → core
  • core не залежить від feature
  • shared не залежить від core
  1. Тестованість з архітектури
  • Компоненти легко мокаються
  • Логіка в сервісах → unit tests
  • Мінімальний TestBed setup
  1. Масштабування команди
  • Чіткі boundaries між фічами
  • Lazy-loaded domains
  • Мінімальні cross-feature залежності

Типові помилки

  • “God components”
  • Глобальні shared services
  • Barrel-файли з side-effects
  • Відсутність lazy loading

Коротко

Великий Angular-застосунок має будуватись за фічами, з standalone + lazy loading, чітким поділом відповідальностей і контрольованим управлінням станом - це основа масштабованості та підтримуваності.

83. Як керувати глобальним станом у програмах Angular?

Angular

Глобальний стан - це дані, які:

  • використовуються в багатьох фічах
  • мають жити довше за окремий компонент
  • повинні бути єдиним джерелом правди

Приклади: auth, user, settings, feature flags.

Основні підходи

  1. NgRx Store (enterprise-рішення)

Коли використовувати

  • Великий застосунок
  • Складна бізнес-логіка
  • Багато асинхронних процесів
  • Потрібен time-travel debugging
store.dispatch(loadUser());
user$ = store.select(selectUser);

Плюси

  • Чітка архітектура
  • Predictable state
  • DevTools

Мінуси

  • Великий boilerplate
  • Overhead для малих проєктів
  1. NgRx ComponentStore (middle ground)

Коли використовувати

  • Feature-level state
  • Складний стан, але без глобального store
@ComponentStore()
export class ProfileStore extends ComponentStore<ProfileState> {}

Плюси

  • Менше boilerplate
  • RxJS-first
  • Добре масштабується
  1. Services + RxJS (класичний підхід)
@Injectable({ providedIn: 'root' })
export class AuthService {
  private userSubject = new BehaviorSubject<User | null>(null);
  user$ = this.userSubject.asObservable();
}

Плюси

  • Простота
  • Швидко реалізувати

Мінуси

  • Легко порушити архітектуру
  • Складно масштабувати
  1. Signals (Angular 20+ - рекомендовано)

Для глобального UI / app-state

@Injectable({ providedIn: 'root' })
export class AppState {
  user = signal<User | null>(null);
}

Плюси

  • Мінімальний boilerplate
  • Висока продуктивність
  • Ідеально для UI-стану

Мінуси

  • Не для складних async flows

Angular 20+ best practices

  • Не зберігати derived state
  • Immutability
  • Чіткі boundaries
  • Signals для UI
  • NgRx тільки коли справді потрібно

Коротко

У Angular глобальний стан керується через Signals, Services або NgRx, і правильний вибір залежить від складності застосунку, а не від моди на інструмент.

84. Які є найкращі практики для зв'язку компонентів у великих додатках Angular?

Angular

  1. Parent → Child (Input / Signals)

Коли

  • Ієрархічний звʼязок
  • Дані зверху вниз
@Input() user!: User;

Angular 20+

Для реактивності - signals

@Input() user = signal<User | null>(null);
  • Простий і прозорий звʼязок
  • Не для далеких компонентів
  1. Child → Parent (Output / Events)

Події знизу вгору

@Output() saved = new EventEmitter<User>();
<app-form (saved)="onSave($event)" />
  • Чітка подієва модель
  • Не масштабувати на багато рівнів
  1. Shared Service (рекомендовано для sibling / distant)
  • Компоненти не повʼязані ієрархічно
  • Потрібен shared state або events
@Injectable({ providedIn: 'root' })
export class UiStateService {
  sidebarOpen = signal(false);
}
this.ui.sidebarOpen.set(true);
  • Слабке звʼязування
  • Добре масштабується
  1. RxJS Subjects (для events / async)
  • Event bus
  • Асинхронні події
private refresh$ = new Subject<void>();
refresh = this.refresh$.asObservable();
  • Не використовувати як global state
  • Завжди asObservable()
  1. Global State (NgRx / Signals)
  • Дані потрібні в багатьох фічах
  • Довготривалий стан (auth, user)
user = this.store.select(selectUser);

або

@Injectable({ providedIn: 'root' })
export class AppState {
  user = signal<User | null>(null);
}
  1. Чого НЕ робити (anti-patterns)
  • Передача через багато рівнів (prop drilling)
  • Виклик методів іншого компонента
  • Глобальні mutable сервіси
  • Shared state без чітких boundaries

Angular 20+ рекомендації

  • Signals - default choice для UI-стану
  • RxJS - для async / streams
  • NgRx - тільки для складного глобального стану
  • Компоненти мають бути dumb, логіка - в сервісах

Коротко

У великих Angular-додатках звʼязок між компонентами має будуватись через Inputs/Outputs для ієрархії, shared services або state-management для віддалених компонентів, уникаючи жорстких залежностей.

85. Чи можна використовувати Angular для створення мобільних застосунків?

Angular

Так. Angular можна використовувати для мобільної розробки трьома основними способами.

  1. Hybrid Mobile Apps (Angular + WebView)
  • Ionic + Angular
  • Capacitor
npm install @ionic/angular

Як працює

  • Angular → HTML/CSS/JS
  • Запускається всередині WebView
  • Один код для iOS / Android

Плюси

  • Швидка розробка
  • Один код-бейс
  • Велика екосистема UI

Мінуси

  • Обмежена native-продуктивність
  1. Progressive Web Apps (PWA)

Це Angular-додаток, який:

  • працює офлайн
  • встановлюється як мобільний app
  • запускається з home screen
ng add @angular/pwa

Плюси

  • Без App Store
  • Один код для web + mobile
  • Швидке оновлення

Мінуси

  • Обмежений доступ до native API
  • iOS має обмеження
  1. Native Mobile Apps (через сторонні фреймворки)

NativeScript + Angular

  • Angular + справжні native UI компоненти

Плюси

  • Максимальна продуктивність
  • Native look & feel

Мінуси

  • Складніша розробка
  • Менша спільнота

Angular 20+ контекст

  • Standalone components добре працюють з Ionic
  • Signals → краща продуктивність UI
  • RxJS → async flows (network, sensors)
  • Один Angular-код → web + mobile

Коротко

Angular підходить для мобільної розробки через Ionic (hybrid), PWA або NativeScript, і вибір залежить від вимог до продуктивності та доступу до native API.

86. Що таке lonic і як він інтегрується з Angular?

Angular

Ionic - це фреймворк для створення кросплатформених застосунків (iOS, Android, Web) на базі web-технологій:

  • HTML
  • CSS
  • JavaScript / TypeScript

Ionic надає:

  • набір готових UI-компонентів, стилізованих під iOS та Material Design
  • інтеграцію з native-можливостями через Capacitor

Як Ionic інтегрується з Angular

Ionic має офіційну Angular-інтеграцію (@ionic/angular) і працює як UI-шар поверх Angular.

npm install @ionic/angular
import { IonicModule } from '@ionic/angular';

bootstrapApplication(AppComponent, {
  providers: [
    importProvidersFrom(IonicModule.forRoot())
  ]
});

Ionic + Angular архітектура

Angular

  • логіка
  • routing
  • DI
  • state management

Ionic

  • UI-компоненти (ion-button, ion-list, ion-modal)
  • mobile UX
  • gestures, animations
<ion-button (click)="save()">Save</ion-button>

Доступ до native API (через Capacitor)

npm install @capacitor/camera
import { Camera } from '@capacitor/camera';

const photo = await Camera.getPhoto({
  resultType: 'uri'
});

Працює на iOS, Android і Web

Переваги Ionic + Angular

  • Один код для web + mobile
  • Повна потужність Angular (standalone, signals, RxJS)
  • Велика бібліотека UI
  • Швидка розробка MVP

Обмеження

  • WebView → не 100% native performance
  • Важчий runtime порівняно з чистим native
  • Не для high-performance 3D / heavy animations

Angular 20+ контекст

  • Standalone components - повністю підтримуються
  • Signals - покращують продуктивність UI
  • Lazy loading - критично важливий для mobile
  • NgRx / Signals - для state management

Коротко

Ionic - це UI-фреймворк для кросплатформених застосунків, який тісно інтегрується з Angular, дозволяючи створювати мобільні та web-апки з одного код-бейсу.

87. Як додати новий компонент, сервіс або модуль за допомогою інтерфейсу командного рядка Angular?

Angular

  1. Створення компонента

Standalone компонент (default у Angular 20+)

ng generate component user
# або коротко
ng g c user

Створюється:

  • user.component.ts

  • user.component.html

  • user.component.css

  • user.component.spec.ts

Компонент standalone за замовчуванням, без NgModule.

Без HTML / CSS (inline)

ng g c user --inline-template --inline-style
  1. Створення сервісу
ng generate service user
# або
ng g s user
@Injectable({ providedIn: 'root' })
export class UserService {}

Сервіс автоматично реєструється в DI.

  1. Створення модуля (legacy / специфічні кейси)
ng generate module admin
# або
ng g m admin

У Angular 20+ NgModule використовується рідко, перевага - standalone.

Створення інших сутностей

Директива

ng g directive highlight

Pipe

ng g pipe capitalize

Guard

ng g guard auth

Resolver

ng g resolver user

Best practices (Angular 20+)

  • Використовувати standalone components

  • Генерувати через CLI для консистентності

  • Не створювати NgModule без потреби

  • Створювати за feature-структурою

Коротко

Angular CLI дозволяє швидко й консистентно створювати компоненти, сервіси та інші сутності; у Angular 20+ standalone-підхід є стандартом, а NgModule використовується лише у виняткових випадках.

88. Які переваги використання інтерфейсу командного рядка Angular для створення каркасів проектів?

Angular

Основні переваги Angular CLI

  1. Швидкий старт проєкту
ng new my-app
  • Готова структура
  • Налаштований білд
  • TypeScript, lint, тестування з коробки
  1. Консистентна архітектура
  • Єдина структура файлів
  • Однакові підходи в усій команді
  • Менше архітектурних помилок
  1. Standalone-first (Angular 20+)
  • Компоненти, директиви, пайпи - standalone за замовчуванням
  • Менше boilerplate
  • Кращий tree-shaking
  1. Автоматичні best practices
  • AOT
  • Production configs
  • Environment files
  • Strict TypeScript
  1. Інтеграція з tooling
  • Vite / build system
  • Testing (unit + e2e)
  • SSR (@angular/ssr)
  • PWA
  • i18n
ng add @angular/pwa
ng add @angular/ssr
  1. Продуктивність і безпека
  • Оптимізовані production-білди
  • Мінімізація
  • Tree shaking
  • Безпечні дефолтні налаштування
  1. Підтримка масштабування
  • Lazy loading
  • Feature-based структура
  • Готовність до enterprise-проєктів

Що було б без CLI

  • Ручна конфігурація білду
  • Непослідовна структура
  • Помилки в налаштуваннях
  • Важкий онбординг нових dev’ів

Коротко

Angular CLI прискорює старт, забезпечує консистентну архітектуру, автоматично застосовує best practices і робить Angular-проєкти масштабованими та підтримуваними з першого дня.

89. Як оновити додаток на Angular до останньої версії за допомогою інтерфейсу командного рядка?

Angular

  1. Перевірити поточну версію
ng version
  1. Оновити Angular CLI глобально
npm install -g @angular/cli@latest

Перевірити:

ng version
  1. Оновити Angular core та CLI в проєкті
ng update @angular/core @angular/cli

CLI:

  • оновить package.json
  • застосує automated migrations
  • покаже breaking changes (якщо є)
  1. Оновити додаткові пакети Angular
ng update @angular/material
ng update @ngrx/store

(за потреби)

  1. Запустити та перевірити застосунок
ng serve
ng test
ng build
  1. Мажорні оновлення (best practice)

Якщо оновлення через кілька major-версій:

ng update @angular/core@19 @angular/cli@19
ng update @angular/core@20 @angular/cli@20

Не стрибати через major-версії

Важливі рекомендації

  • Перед оновленням зробити commit
  • Читати output CLI (warnings / TODO)
  • Не оновлювати вручну package.json
  • Використовувати офіційні migrations

Angular 20+ після оновлення

Рекомендується:

  • перейти на standalone components
  • перевірити deprecated API
  • оновити RxJS
  • увімкнути stricter TypeScript
  • переглянути zone / zoneless можливості

Коротко

Оновлення Angular виконується через ng update, яке автоматично застосовує міграції, оновлює залежності та допомагає безпечно перейти на останню версію фреймворку.

90. Як можна інтегрувати сторонні бібліотеки в застосунок Angular?

Angular

  1. Встановлення через npm (основний спосіб)
npm install lodash
import { debounce } from 'lodash';
  • Tree-shaking
  • Типізація (якщо є)
  • Рекомендований підхід
  1. Бібліотеки з Angular-обгорткою (preferred)

Приклад: Angular Material, ngx-translate, NgRx

npm install @angular/material
import { MatButtonModule } from '@angular/material/button';
  • Нативна інтеграція з Angular
  • DI, change detection, SSR-friendly
  1. Глобальні JS-бібліотеки (legacy)

Додавання через angular.json

"scripts": ["node_modules/some-lib/lib.js"]

Використання

declare const SomeLib: any;
  • Не tree-shakable
  • Не рекомендовано для нових проєктів
  1. Типізація бібліотек

Якщо типів немає:

npm install -D @types/library-name

або створити вручну:

declare module 'legacy-lib';
  1. Dynamic import (для важких бібліотек)
async loadChart() {
  const { Chart } = await import('chart.js');
}
  • Code splitting
  • Менший initial bundle
  1. Інтеграція через сервіс (best practice)
@Injectable({ providedIn: 'root' })
export class ChartService {
  async load() {
    const lib = await import('chart.js');
    return lib.Chart;
  }
}
  • Інкапсуляція + testability
  1. Angular 20+ рекомендації
  • Віддавати перевагу npm + ES modules
  • Lazy-load важкі бібліотеки
  • Не підключати глобальні скрипти без потреби
  • Обгортати бібліотеки у сервіси
  • Перевіряти SSR-сумісність

Типові помилки

  • Підключення через <script> у index.html
  • Відсутність типів
  • Використання browser-only API без перевірки платформи
  • Імпорт всієї бібліотеки замість named imports

Коротко

Сторонні бібліотеки в Angular найкраще інтегрувати через npm + ES imports, за потреби - lazy loading, обгортати у сервіси та уникати глобальних скриптів для кращої продуктивності й підтримуваності.

91. Що таке змінні середовища в Angular і як їх використовувати?

Angular

У Angular змінні середовища - це конфігураційні значення, які:

  • відрізняються між development, production, staging
  • використовуються для:
    • API URLs
    • feature flags
    • логування
    • інтеграцій із сервісами

Класичний механізм Angular (environment files)

Файли середовищ

src/environments/
 ├─ environment.ts
 └─ environment.prod.ts

Приклад environment.ts

export const environment = {
  production: false,
  apiUrl: 'http://localhost:3000',
};

Приклад environment.prod.ts

export const environment = {
  production: true,
  apiUrl: 'https://api.example.com',
};

Використання в коді

import { environment } from '../environments/environment';

this.http.get(`${environment.apiUrl}/users`);

Angular підміняє файл автоматично під час build.

Як відбувається підміна

У angular.json:

"configurations": {
  "production": {
    "fileReplacements": [
      {
        "replace": "src/environments/environment.ts",
        "with": "src/environments/environment.prod.ts"
      }
    ]
  }
}

Angular 20+ контекст (сучасний підхід)

Build-time змінні

  • Environment файли - build-time
  • Після білду значення зашиті в JS
  • Не можна змінити без нового build

Runtime environment (для SSR / Docker)

Для великих систем часто використовують runtime config:

window.__env = {
  apiUrl: 'https://api.example.com'
};
export const API_URL = window.__env.apiUrl;
  • Один build → різні середовища
  • Підходить для SSR / Kubernetes

Чого НЕ варто робити

  • Зберігати секрети (API keys, passwords)
  • Вважати environment secure
  • Міняти env без rebuild (build-time vars)

Best practices

  • Environment → тільки публічна конфігурація
  • Secrets → тільки на бекенді
  • Для enterprise:
    • Runtime config + SSR
  • Типізуйте environment
interface Env { production: boolean; apiUrl: string; }

Коротко

Змінні середовища в Angular - це build-time конфігурація, яка дозволяє використовувати різні налаштування для dev/prod; для складних систем застосовують runtime environment, але секрети ніколи не зберігають у frontend.

92. Чи можна використовувати веб-воркери в застосунках Angular і як?

Angular

Так. Angular підтримує Web Workers і дозволяє виконувати важкі обчислення у фоновому потоці, не блокуючи UI.

Навіщо Web Workers

  • Винести CPU-heavy задачі з main thread
  • Уникнути фризів UI
  • Покращити responsiveness

Типові кейси:

  • Обробка великих масивів
  • Криптографія
  • Парсинг файлів
  • Data processing (charts, analytics)

Створення Web Worker через Angular CLI

ng generate web-worker app
# або
ng g web-worker app

Створюється файл:

src/app/app.worker.ts

Код Web Worker

// <reference lib="webworker" />

addEventListener('message', ({ data }) => {
  const result = data * 2; // важка операція
  postMessage(result);
});

Використання в Angular-компоненті

if (typeof Worker !== 'undefined') {
  const worker = new Worker(
    new URL('./app.worker', import.meta.url)
  );

  worker.onmessage = ({ data }) => {
    console.log('Result:', data);
  };

  worker.postMessage(10);
}

Обмеження Web Workers

Немає доступу до:

  • DOM
  • window, document
  • Angular DI
  • Services, HttpClient

Доступно:

  • Чистий JS/TS
  • Message passing
  • Pure logic

Best practices

  • Передавайте простi данi (structured clone)
  • Тримайте логіку pure
  • Не створюйте багато workers
  • Для async IO → RxJS (не worker)
  • Для UI state → signals

Angular 20+ контекст

  • Працює з standalone components
  • Не залежить від zones / zoneless
  • Добре поєднується з RxJS (fromEvent)

Коротко

Web Workers в Angular використовуються для виконання важких обчислень у фоновому потоці, створюються через Angular CLI і спілкуються з застосунком через postMessage, покращуючи продуктивність UI.

93. Як обробляти налаштування конфігурації в Angular?

Angular

  1. Build-time конфігурація (стандарт Angular)

Environment файли

src/environments/
 ├─ environment.ts
 └─ environment.prod.ts
// environment.ts
export const environment = {
  production: false,
  apiUrl: 'http://localhost:3000',
};
// використання
import { environment } from '../environments/environment';
this.http.get(`${environment.apiUrl}/users`);

Плюси: простота, оптимізація Мінуси: значення «зашиті» в білд (потрібен rebuild)

  1. Runtime конфігурація (enterprise / SSR / Docker)

Завантаження конфігурації при старті

@Injectable({ providedIn: 'root' })
export class AppConfigService {
  config!: { apiUrl: string };

  load() {
    return fetch('/assets/config.json')
      .then(r => r.json())
      .then(c => (this.config = c));
  }
}
// app.config.ts
providers: [{
  provide: APP_INITIALIZER,
  useFactory: (cfg: AppConfigService) => () => cfg.load(),
  deps: [AppConfigService],
  multi: true,
}]

Плюси: один білд → різні середовища Мінуси: трохи більше складності

  1. Dependency Injection для конфігурації
export const API_URL = new InjectionToken<string>('API_URL');

providers: [{ provide: API_URL, useValue: environment.apiUrl }]
constructor(@Inject(API_URL) private apiUrl: string) {}

Плюси: типобезпечно, тестабельно

  1. Feature flags (рекомендовано через Signals)
@Injectable({ providedIn: 'root' })
export class FeatureFlags {
  newUI = signal(false);
}
<section *ngIf="flags.newUI()">...</section>

Best practices

  • Environment - для build-time конфігів
  • Runtime config - для enterprise/SSR
  • DI tokens - для доступу до конфігів
  • Не зберігати секрети у фронтенді
  • Типізувати конфігурацію
  • Ініціалізувати до старту (APP_INITIALIZER)

Коротко

В Angular конфігурацію керують через environment файли (build-time) або runtime-завантаження + DI; вибір залежить від вимог до деплою, SSR та масштабування.

94. Опишіть процес обміну даними між непов'язаними компонентами.

Angular

  1. Shared Service + Signals (рекомендовано)
  • UI- або app-level стан
  • Мінімальний boilerplate
  • Висока продуктивність
@Injectable({ providedIn: 'root' })
export class UiStateService {
  sidebarOpen = signal(false);
}
// будь-який компонент
this.ui.sidebarOpen.set(true);
<div *ngIf="ui.sidebarOpen()">...</div>
  • Простий, типобезпечний
  • Ідеально для Angular 20+
  1. Shared Service + RxJS (events / async)
  • Подієва модель
  • Асинхронні потоки
@Injectable({ providedIn: 'root' })
export class RefreshService {
  private refresh$ = new Subject<void>();
  refresh = this.refresh$.asObservable();

  trigger() {
    this.refresh$.next();
  }
}
this.refreshService.refresh.subscribe(() => reload());
  • Не використовувати як глобальний state
  • Завжди asObservable()
  1. NgRx Store (глобальний стан)
  • Дані потрібні у багатьох фічах
  • Складна бізнес-логіка
  • Потрібен time-travel debugging
this.store.dispatch(loadUser());
user$ = this.store.select(selectUser);
  • Масштабованість
  • Великий boilerplate
  1. Router State / Params (контекст навігації)
  • Дані повʼязані з навігацією
this.router.navigate(['/details'], {
  state: { id: 1 }
});
const id = history.state.id;
  • Тимчасово, не для довготривалого стану

Чого НЕ робити (anti-patterns)

  • Передавати дані через багато рівнів (prop drilling)
  • Викликати методи іншого компонента
  • Використовувати глобальні mutable сервіси
  • Змішувати events і state в одному Subject

Angular 20+ рекомендації

  • Signals - default для стану
  • RxJS - для асинхронних потоків
  • NgRx - лише коли виправдано складністю
  • Компоненти мають бути dumb, логіка - в сервісах

Коротко

Для обміну даними між неповʼязаними компонентами в Angular використовують shared services (signals або RxJS), global state (NgRx) або router state, уникаючи жорстких залежностей між компонентами.

95. Які популярні IDE для розробки Angular є та які функції вони пропонують для розробників?

Angular

  1. Visual Studio Code (VS Code)

Найпопулярніший вибір для Angular

Основні можливості

  • TypeScript IntelliSense (автодоповнення, перевірка типів)
  • Angular Language Service
    • Автодоповнення для шаблонів (*ngFor, ngIf, async)
    • Перехід до визначення (Go to Definition)
    • Error reporting у HTML-шаблонах
  • Emmet
  • Debugger для Chrome/Edge
  • Extensions
    • Angular Snippets
    • ESLint
    • Prettier
    • Nx / Nrwl support
    • Jest / Vitest
  • Terminal / Git / Tasks вбудовані

Інтеграції та зручності

  • Hotkeys, Refactoring
  • Workspace settings
  • Multi-root support
  • Remote Development
  1. WebStorm (JetBrains)

Потужний комерційний IDE з глибокою підтримкою Angular

Основні можливості

  • Вбудований Angular support
  • Advanced refactorings
  • Code analysis & inspections
  • Navigation & find usages
  • Smart imports
  • Live templates
  • Integrated debugger

Переваги

  • Більш “все-в-одному” ніж VS Code
  • Краща підтримка великих проєктів

Потрібна ліцензія

  1. IntelliJ IDEA Ultimate

Розширена версія WebStorm плюс backend support

Можливості

  • Angular + full-stack (Node / Java / Spring) support
  • Unified development experience
  • Built-in REST client
  • Database tools

Ідеально для enterprise-команд

  1. Sublime Text

Легкий редактор з плагінами для Angular

Можливості через плагіни

  • TypeScript support
  • Angular snippets
  • Build system integration

Менше “розумних” фіч, ніж у VS Code/WebStorm

  1. Vim / Neovim

Максимальна кастомізація через конфіг та плагіни

Можливості

  • coc.nvim / LSP (TypeScript + Angular Language Service)
  • Snippets
  • Fuzzy finder
  • Git integration

Підходить профі; steep learning curve

  1. Emacs

Гнучкий редактор із LSP підтримкою

Можливості

  • TypeScript + Angular LSP integration
  • Smart completion
  • Custom workflows

Потрібне налаштування

  1. StackBlitz / GitHub Codespaces

Онлайн-середовища для Angular

Переваги

  • Немає локального оточення
  • Швидкий прототип
  • Live preview
  • Інтеграція з GitHub

Angular 20+ контекст

  • Modern editors/IDEs чудово працюють з:
    • Standalone components
    • Signals
    • Vite-based builds
    • RxJS patterns
  • Розширення CLI інтегрується з Hotkeys / Tasks

Коротко

Найчастіше Angular-розробники використовують VS Code (light, extensible) або WebStorm/IntelliJ (потужний IDE). Обидва дають автодоповнення, підтримку Angular Language Service, refactoring, debugger, інтеграцію з Git, тестами та TypeScript.

96. Як налагоджувати застосунки Angular?

Angular

  1. Browser DevTools (основа)

Console

  • console.log / warn / error
  • Логи в компонентах, сервісах, effects
console.log('User:', this.user());

Sources

  • Breakpoints у TS (source maps)
  • Step over / into
  1. Debugger у IDE (VS Code / WebStorm)
  • Запуск ng serve
  • Attach до Chrome/Edge
  • Breakpoints у TypeScript
// .vscode/launch.json (спрощено)
{
  "type": "chrome",
  "request": "attach",
  "port": 9222
}
  1. Angular DevTools (обовʼязково)

Можливості

  • Component tree
  • Inputs / Outputs
  • Signals state
  • Change Detection cycles
  • Performance profiling

Працює для standalone, signals, OnPush

  1. Debugging Change Detection
  • Перевіряти зайві ререндери
  • Використовувати OnPush
changeDetection: ChangeDetectionStrategy.OnPush
  • У signals - дивитись, що тригерить computed()
  1. RxJS Debugging

tap для логування

this.users$
  .pipe(tap(v => console.log(v)))
  .subscribe();

Контроль підписок

.pipe(takeUntilDestroyed())
  1. HTTP Debugging
  • Network tab (requests / headers / payload)
  • Http Interceptors для логів
export const logInterceptor = (req, next) => {
  console.log(req.url);
  return next(req);
};
  1. Template Debugging
<pre>{{ user() | json }}</pre>
  • Перевірка *ngIf, *ngFor, trackBy
  1. Production Debugging
  • Source maps (обережно)
  • Centralized logging (Sentry, LogRocket)
  • Feature flags для safe toggles

Angular 20+ поради

  • Signals → легше відстежувати state
  • Zoneless → менше “магії”, простіше дебажити
  • Standalone → менше контексту, швидше пошук проблем
  • inject() → прозорий DI

Типові помилки

  • Debug через console.log без breakpoints
  • Відсутні source maps
  • Ручні subscribe() без lifecycle-контролю
  • Немає trackBy у великих списках

Коротко

Angular-дебагінг базується на Browser DevTools + Angular DevTools + IDE debugger; у Angular 20+ signals і standalone значно спрощують відстеження стану та change detection.

97. Поясніть, як використовувати Angular DevTools.

Angular

Angular DevTools - це browser extension (Chrome / Edge), який дозволяє:

  • інспектувати дерево компонентів
  • аналізувати change detection
  • профілювати performance
  • переглядати signals / inputs / outputs

Встановлення

  • Chrome Web Store → Angular DevTools
  • Працює у dev-режимі Angular

Основні інструменти для профілювання

  1. Components Tree

Дозволяє:

  • переглянути ієрархію компонентів
  • побачити OnPush / Default CD
  • швидко знайти “важкі” компоненти

Корисно для:

  • пошуку надмірної вкладеності
  • аналізу архітектури
  1. Change Detection Profiler (ключовий)

Як використовувати

  1. Відкрити Profiler
  2. Натиснути Start profiling
  3. Взаємодіяти з UI
  4. Натиснути Stop

Що показує

  • Скільки разів кожен компонент перевірявся
  • Час виконання CD
  • Компоненти, які перерендерюються без потреби

Типові висновки:

  • де потрібен OnPush
  • де мутації state
  • де відсутній trackBy
  1. Signals Debugging (Angular 16+ / 20+)
  • Перегляд значень signal()
  • Відстеження, що тригерить computed()
  • Пошук зайвих recompute

Значно простіше, ніж RxJS debugging

  1. Performance + Browser DevTools

Angular DevTools добре комбінується з:

  • Chrome Performance tab
  • Timeline
  • FPS / scripting time

Можна звʼязати Angular CD з browser repaint

Типові performance-проблеми, які знаходять через DevTools

  • Відсутній ChangeDetectionStrategy.OnPush
  • Мутація обʼєктів замість immutability
  • Відсутній trackBy у *ngFor
  • Impure pipes
  • Зайві subscriptions
  • Великий global state

Angular 20+ best practices для профілювання

  • Використовувати signals для UI-стану
  • OnPush - default
  • Lazy loading фіч
  • Мінімізувати global change detection
  • Zoneless → простіший performance model

Коротко

Angular DevTools (Augury) - ключовий інструмент для аналізу продуктивності Angular: він показує дерево компонентів, частоту change detection та дозволяє швидко знайти performance bottlenecks у сучасних Angular-застосунках.

98. Як інтегрувати Angular з іншими фреймворками або бібліотеками, такими як React або Vue.js?

Angular

Коли взагалі потрібна інтеграція

  • Міграція legacy-застосунку
  • Micro-frontend архітектура
  • Спільне використання UI між різними командами
  • Вставка ізольованого віджета (widget)
  • Поступовий перехід між фреймворками
  1. Web Components (рекомендований підхід)

Кожен фреймворк експортує UI як custom element, незалежний від реалізації.

Angular → Web Component

import { createCustomElement } from '@angular/elements';

const element = createCustomElement(AppComponent, { injector });
customElements.define('my-angular-app', element);
<my-angular-app></my-angular-app>

Переваги

  • Повна ізоляція
  • Працює з Angular / React / Vue
  • Незалежні деплои
  • Framework-agnostic

Недоліки

  • Більший bundle
  • Обмежений shared state
  1. Micro-frontends (Module Federation)

Кожен фреймворк - окремий remote app.

Shell (Angular)
 ├─ Angular remote
 ├─ React remote
 └─ Vue remote

Інструменти

  • Webpack Module Federation
  • Nx
  • Single-SPA

Переваги

  • Enterprise-ready
  • Незалежні команди
  • Незалежні релізи

Недоліки

  • Висока складність
  • Архітектурна дисципліна
  1. Вбудовування через iframe (простий, але грубий)
<iframe src="https://react-app.example.com"></iframe>

Плюси

  • Максимальна ізоляція
  • Мінімум інтеграції

Мінуси

  • Поганий UX
  • Складний communication
  • SEO проблеми
  1. Використання сторонніх бібліотек (не фреймворків)

Приклад: React-based library в Angular

Не рекомендовано напряму

Краще:

  • знайти framework-agnostic версію
  • або wrapper
  • або винести в Web Component
  1. Shared state між фреймворками

Варіанти

  • Custom events
  • postMessage
  • URL / Router state
  • Shared backend (API-driven state)

Не ділити напряму Angular Store / Signals з React

Angular 20+ рекомендації

  • Web Components - default choice
  • Micro-frontends - для enterprise
  • Не змішувати Angular і React в одному runtime
  • Не імпортувати React у Angular напряму
  • Чіткі boundaries між системами

Типові anti-patterns

  • Angular component всередині React tree напряму
  • Спільний глобальний state між фреймворками
  • Tight coupling між lifecycle фреймворків

Коротко

Angular можна інтегрувати з React або Vue через Web Components або micro-frontends. Найкращий підхід - ізоляція, а не пряме змішування фреймворків у одному runtime.

99. Чи можна вбудувати застосунок Angular в інший застосунок?

Angular

Так, можна. Існує кілька підходів залежно від рівня інтеграції та вимог до ізоляції.

  1. Web Components (Angular Elements) - рекомендовано

Angular app/компонент експортується як custom element і використовується в будь-якому середовищі.

import { createCustomElement } from '@angular/elements';

const el = createCustomElement(AppComponent, { injector });
customElements.define('my-angular-app', el);
<my-angular-app></my-angular-app>

Плюси

  • Framework-agnostic
  • Ізоляція
  • Просте вбудовування

Мінуси

  • Більший bundle
  • Обмежений shared state
  1. Micro-frontends (Module Federation / single-spa)

Коли

  • Великий enterprise
  • Незалежні команди/релізи

Плюси

  • Незалежні деплои
  • Масштабованість

Мінуси

  • Висока складність
  • Потрібна архітектурна дисципліна
  1. iframe (простий, але грубий)
<iframe src="https://angular-app.example.com"></iframe>

Плюси

  • Максимальна ізоляція
  • Мінімум інтеграції

Мінуси

  • Гірший UX
  • Складний обмін даними
  • SEO/перформанс обмеження
  1. Вбудований віджет (script + bootstrap)
  • Angular app завантажується як віджет
  • Комунікація через Custom Events

Менш рекомендовано, ніж Web Components

Обмін даними між хостом і Angular

  • Custom Events
  • postMessage
  • URL params
  • API (backend як джерело правди)

Не ділити напряму Angular state (Signals/NgRx) з хостом

Angular 20+ рекомендації

  • Web Components - default
  • Micro-frontends - для enterprise
  • Не змішувати runtime різних фреймворків напряму
  • Чіткі boundaries та контракти

Коротко

Angular-застосунок можна вбудувати в інший застосунок. Найкращі підходи - Web Components або micro-frontends; iframe - лише для простих або legacy кейсів.

100. Які проблеми можуть бути під час оновлення Angular-застосунку до новішої версії?

Angular

Основні категорії проблем

  1. Breaking changes Angular API
  • Видалені або deprecated API
  • Зміни в поведінці Router, Forms, DI
  • Обовʼязкові міграції

Приклад

  • Застарілі lifecycle hooks / API
  • Зміни в SSR або hydration

Рішення: уважно читати output ng update і changelog

  1. Несумісність сторонніх бібліотек
  • Бібліотека не підтримує нову версію Angular
  • Peer dependency conflicts
npm ERR! peer dep missing

Рішення:

  • Оновлювати бібліотеки по черзі
  • Перевіряти compatibility matrix
  • За потреби - тимчасові заміни
  1. TypeScript / RxJS оновлення
  • Строгіші типи
  • Помилки компіляції
  • Зміни в RxJS операторах
// раніше проходило
someValue!.property

Рішення:

  • Виправляти типи
  • Не вимикати strict mode
  • Оновлювати RxJS поступово
  1. Зміни в архітектурі (Angular 16+ → 20+)
  • Перехід на standalone components
  • Менше NgModules
  • Нові підходи (signals, inject())

Проблема: legacy-код виглядає застарілим Рішення: мігрувати поступово, не все одразу

  1. SSR / Build / Tooling
  • Зміни в build system (Vite)
  • SSR API
  • Hydration issues

Рішення:

  • Перевіряти SSR окремо
  • Тестувати production build
  1. Тести ламаються
  • Jasmine/Karma конфлікти
  • Застарілі TestBed патерни
  • Async timing issues

Рішення:

  • Оновити тест-раннер
  • Перейти на Jest / Vitest (за можливості)
  1. Performance регресії
  • Зайві change detection цикли
  • Відсутній OnPush
  • Legacy patterns без signals

Рішення:

  • Angular DevTools
  • OnPush + signals
  • trackBy у списках

Best practices для безпечного оновлення

  • Завжди commit перед оновленням
  • Оновлювати по major-версіях
  • Використовувати тільки ng update
  • Читати warnings CLI
  • Проганяти тести після кожного кроку

Коротко

Основні проблеми при оновленні Angular - це breaking changes, несумісні бібліотеки, строгіші типи та legacy-архітектура. Вирішуються поетапним оновленням, офіційними міграціями та хорошим тест-покриттям.

101. Що таке Signals в Angular і які їх основні типи?

Signals - це нова реактивна примітивна модель в Angular, яка дозволяє відслідковувати залежності між станом і UI на рівні окремих виразів (fine-grained reactivity).

Signals замінюють імперативний change detection і зменшують потребу у Zone.js.

Основні типи signals:

signal() - writable signal для зберігання стану

count = signal(0);
count.set(1);
count.update(v => v + 1);

computed() - derived signal, що залежить від інших signals

doubleCount = computed(() => this.count() * 2);

effect() - side effects при зміні сигналів

effect(() => {
  console.log(this.count());
});

Signal-based inputs / outputs:

  • input() - реактивна альтернатива @Input
  • output() - signal-based події
  • model() - двосторонній binding на основі signals
value = input<number>();
changed = output<number>();
state = model<string>();

Коротко:

Signals - це основа сучасної реактивності Angular і ключ до zoneless архітектури.

102. Що таке @defer і як він використовується в Angular?

@defer - це механізм відкладеного рендерингу шаблонів, який дозволяє завантажувати та відображати контент лише за певних умов.

Використовується для:

  • покращення performance
  • зменшення initial load
  • оптимізації роботи з DOM
@defer {
  <heavy-component />
} @placeholder {
  <p>Loading...</p>
} @error {
  <p>Error loading content</p>
}

Підтримувані тригери:

  • on viewport
  • on idle
  • on interaction
  • on timer

Коротко:

@defer - declarative lazy rendering для компонентів і DOM.

103. Які особливості @for у порівнянні з *ngFor?

@for - це новий control flow синтаксис, оптимізований для сучасного Angular.

Основні відмінності:

Обовʼязковий track

@for (item of items; track item.id) {
  <div>{{ item.name }}</div>
}

Підтримка @empty

@for (item of items; track item.id) {
  <div>{{ item.name }}</div>
} @empty {
  <p>No items</p>
}
  • Краща інтеграція з signals
  • Менше runtime overhead

Коротко:

@for - більш явний, безпечний та продуктивний механізм рендерингу списків.

104. Що таке Content Projection в Angular?

Content Projection - це механізм вставки зовнішнього контенту всередину компонента.

Основні інструменти:

ng-content - projection слот

<ng-content></ng-content>

select - множинні слоти

<ng-content select="[header]"></ng-content>
<ng-content select="[body]"></ng-content>

ng-template - шаблони для умовного або відкладеного рендерингу

<ng-template #tpl>
  <p>Projected template</p>
</ng-template>

Використовується для:

  • reusable UI components
  • layout components
  • design systems

Коротко:

Content Projection дозволяє будувати гнучкі, композиційні компоненти.

About

Найпопулярніші запитання та відповіді на співбесіді з Angular

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project

  •  

Packages

No packages published