https://github.com/devloversteam/angular-interview-questions
https://github.com/devloversteam/angular-interview-questions
Last synced: 5 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/devloversteam/angular-interview-questions
- Owner: DevLoversTeam
- License: mit
- Created: 2025-09-24T09:01:04.000Z (10 months ago)
- Default Branch: main
- Last Pushed: 2025-10-04T08:24:07.000Z (10 months ago)
- Last Synced: 2025-10-04T09:21:10.537Z (10 months ago)
- Size: 205 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Contributing: .github/CONTRIBUTING.md
- Funding: .github/FUNDING.yml
- License: LICENSE.txt
- Code of conduct: CODE_OF_CONDUCT.md
- Security: SECURITY.md
Awesome Lists containing this project
README
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:
```HTML
{{ userName }}
```
2. **Property binding** - передача значень у властивості
DOM-елементів/компонентів:
```HTML
```
3. **Event binding** - реакція на події DOM:
```HTML
Save
```
4. **Two-way binding** - синхронізація стану між шаблоном і компонентом
([(...)]):
```HTML
```
**Коротко**
В 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 тощо).
#### Використання:
```TypeScript
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-user-card',
standalone: true,
template: `
{{ name() }}
Change
`
})
export class UserCardComponent {
name = signal('Viktor');
changeName() {
this.name.set('Updated Name');
}
}
```
У шаблоні іншого компонента можна підключити:
```HTML
```
**Коротко**
Компонент = ізольований блок 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,
- керування станом,
- інкапсуляції логіки поза компонентом.
#### Приклад:
```TypeScript
import { Injectable, signal } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class UserService {
userName = signal('Guest');
setUser(name: string) {
this.userName.set(name);
}
}
```
#### Використання у компоненті:
```TypeScript
import { Component, inject } from '@angular/core';
import { UserService } from './user.service';
@Component({
selector: 'app-header',
standalone: true,
template: `
Welcome, {{ userService.userName() }}
`
})
export class HeaderComponent {
userService = inject(UserService);
}
```
**Коротко**
Сервіс створюють через `@Injectable`, а використовують для бізнес-логіки та
спільного стану між компонентами.
7. Поясни, що таке dependency injection (DI) в Angular.
#### Angular
Dependency Injection (DI) - це механізм Angular, який автоматично створює та
надає об’єкти (сервіси, токени) компонентам чи іншим сервісам замість ручного
створення через new.
#### Навіщо:
- спрощує тестування (можна підмінити залежності mock-ами),
- забезпечує повторне використання сервісів,
- керує життєвим циклом об’єктів (singleton, scoped).
#### Приклад:
```TypeScript
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class ApiService {
getData() {
return ['item1', 'item2'];
}
}
```
#### Використання у компоненті:
```TypeScript
import { Component, inject } from '@angular/core';
import { ApiService } from './api.service';
@Component({
selector: 'app-list',
standalone: true,
template: `
})
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.
#### Приклад старого підходу:
```TypeScript
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
bootstrap: [AppComponent]
})
export class AppModule {}
```
#### Актуальний підхід (Angular 20, без модуля):
```TypeScript
bootstrapApplication(AppComponent, {
providers: []
});
```
**Коротко**
Модулі в Angular зараз - це легасі-інструмент, який замінено на standalone
компоненти. Їхня головна роль сьогодні - лише для підтримки старого коду чи
бібліотек.
9. Як обробляти події в Angular?
#### Angular
В Angular події обробляються через event binding, тобто підписку на подію DOM
або кастомної події компонента.
#### Синтаксис:
```HTML
Click me
```
#### У компоненті:
```ts
import { Component } from '@angular/core';
@Component({
selector: 'app-button',
standalone: true,
template: `Click me`,
})
export class ButtonComponent {
onClick() {
console.log('Button clicked!');
}
}
```
#### Кастомна подія (для дочірнього компонента):
```TypeScript
import { Component, EventEmitter, Output } from '@angular/core';
@Component({
selector: 'app-child',
standalone: true,
template: `Notify`
})
export class ChildComponent {
@Output() notify = new EventEmitter();
notifyParent() {
this.notify.emit('Hello from child');
}
}
```
#### У батьківському компоненті:
```HTML
```
Коротко: в Angular події обробляються через `(eventName)="handler()"` для DOM та
через `@Output` + `EventEmitter` для кастомних подій.
10. Що таке двостороннє зв’язування (two-way binding) і як його реалізувати в Angular?
#### Angular
Двостороннє зв’язування (two-way binding) - це синхронізація стану між
компонентом і шаблоном, коли:
- зміни в UI оновлюють стан компонента,
- зміни в компоненті автоматично відображаються в UI.
#### Класичний підхід (ngModel, template-driven forms):
```HTML
Hello, {{ name }}
```
```TypeScript
@Component({
selector: 'app-input',
standalone: true,
template: ``
})
export class InputComponent {
name = 'Evan';
}
```
#### Сучасний підхід з Signals (локальний стан):
```TypeScript
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-input',
standalone: true,
template: `
Hello, {{ name() }}
`
})
export class InputComponent {
name = signal('Evan');
}
```
Signals забезпечують реактивність, але two-way binding тут реалізується вручну
через event → set().
#### Two-way binding між компонентами з model():
```TypeScript
import { Component, model } from '@angular/core';
@Component({
selector: 'app-input',
standalone: true,
template: `
`
})
export class InputComponent {
name = model('Evan');
}
```
```HTML
```
**Коротко**
- `ngModel` - legacy two-way binding
- `signal()` - сучасна реактивність (локальний стан)
- `model()` - рекомендований спосіб two-way binding у сучасному Angular
11. Поясни різницю між компонентом і директивою в Angular?
#### Angular
- Компонент
- це спеціальний тип директиви, який має шаблон (HTML) + стилі + логіку;
- використовується для створення UI-елементів;
- приклад: `@Component({ selector: 'app-user', template: '
User
' })`.- Директива
- не має власного шаблону;
- змінює поведінку або вигляд існуючих елементів/компонентів;
- може бути structural (`@if`, `@for`) або attribute (`ngClass`, `ngStyle`).
#### Приклад кастомної директиви (attribute):
```TypeScript
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');
}
}
```
Використання у шаблоні:
```HTML
Text with highlight
```
**Коротко**
компонент = директива + шаблон, а директива = поведінка без власного UI.
12. Що таке пайпи (Pipes) в Angular та де їх варто використовувати?
#### Angular
Pipe - це клас, який трансформує дані без зміни їхнього оригінального стану.
Використовується у шаблонах для форматування значень.
#### Приклади вбудованих пайпів:
- `date` → форматування дат
- `currency` → вивід валют
- `uppercase` / `lowercase` → зміна регістру
- `async` → робота з Promise / Observable
#### Приклад використання:
```HTML
{{ today | date:'dd/MM/yyyy' }}
{{ price | currency:'USD' }}
```
#### Кастомний pipe:
```TypeScript
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'exclaim',
standalone: true
})
export class ExclaimPipe implements PipeTransform {
transform(value: string): string {
return value + '!';
}
}
```
У шаблоні:
```HTML
{{ 'Hello' | exclaim }}
```
**Коротко**
Pipes потрібні для форматування та трансформації даних у шаблоні, щоб не
захаращувати логіку компонента.
13. Як обробляти надсилання форм (form submissions) в Angular?
#### Angular
**В Angular є два основні підходи:**
1. **Template-driven forms** (простий варіант, з `ngModel`):
```HTML
Send
```
```TypeScript
onSubmit(value: any) {
console.log('Form submitted:', value);
}
```
2. **Reactive forms** (рекомендований для складних кейсів):
```TypeScript
import { Component } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-login',
standalone: true,
imports: [ReactiveFormsModule],
template: `
Login
`
})
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).
#### Приклад сервісу:
```TypeScript
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');
}
}
```
#### Використання у компоненті:
```TypeScript
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: `
- {{ user.name }}
`
})
export class UsersComponent {
api = inject(ApiService);
users$ = this.api.getUsers();
}
```
**Коротко**
В Angular 20 HTTP-запити робляться через HttpClient, а результат часто
обробляється в шаблоні через async pipe.
16. Як передати дані з батьківського компонента до дочірнього?
#### Angular
Передача даних відбувається через input-зв’язування (@Input() декоратор).
Батьківський компонент передає значення дочірньому через атрибут у шаблоні.
#### Приклад:
**child.component.ts**
```TypeScript
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-child',
standalone: true,
template: `
Message: {{ message }}
`})
export class ChildComponent {
@Input() message = '';
}
```
**parent.component.ts**
```TypeScript
import { Component } from '@angular/core';
import { ChildComponent } from './child.component';
@Component({
selector: 'app-parent',
standalone: true,
imports: [ChildComponent],
template: ``
})
export class ParentComponent {
parentMessage = 'Hello from Parent!';
}
```
**Коротко:**
- Дані від батька до дитини передаються через @Input() - це property binding
[property]="value".
17. Як передати подію або дані від дочірнього компонента до батьківського?
#### Angular
Для передачі подій вгору використовується @Output() разом із EventEmitter.
Дочірній компонент «викидає» подію, а батьківський підписується на неї через
(eventName) у шаблоні.
**child.component.ts**
```TypeScript
import { Component, EventEmitter, Output } from '@angular/core';
@Component({
selector: 'app-child',
standalone: true,
template: `Send`
})
export class ChildComponent {
@Output() message = new EventEmitter();
sendMessage() {
this.message.emit('Hello from Child!');
}
}
```
**parent.component.ts**
```TypeScript
import { Component } from '@angular/core';
import { ChildComponent } from './child.component';
@Component({
selector: 'app-parent',
standalone: true,
imports: [ChildComponent],
template: ``
})
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()** | Перед знищенням компоненту | Очищення підписок, таймерів, ресурсів |
#### Приклад:
```TypeScript
import { Component, OnInit, OnDestroy } from '@angular/core';
@Component({
selector: 'app-demo',
standalone: true,
template: `
Lifecycle demo
`})
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** | Без інкапсуляції. | Стилі поширюються глобально на весь застосунок. |
#### Приклад:
```TypeScript
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]** | `
| **[ngStyle]** | `` | Застосовує стилі напряму через об’єкт. |
| **Класова прив’язка** | `` | Додає клас, якщо умова `true`. |
| **Стильова прив’язка** | `` | Змінює конкретний 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` у шаблоні. |
#### Приклад кастомної структурної директиви:
```TypeScript
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[appUnless]',
standalone: true
})
export class UnlessDirective {
constructor(
private templateRef: TemplateRef,
private viewContainer: ViewContainerRef
) {}
@Input() set appUnless(condition: boolean) {
this.viewContainer.clear();
if (!condition) {
this.viewContainer.createEmbeddedView(this.templateRef);
}
}
}
```
#### Використання у шаблоні:
```HTML
You are not logged in!
```
**Коротко:**
Кастомна структурна директива керує DOM через `ViewContainerRef` і
`TemplateRef`. Використовується з `*` синтаксисом у шаблоні.
23. Як зробити сервіс singleton в Angular?
#### Angular
У Angular singleton-сервіс - це сервіс, який створюється лише один раз і
використовується у всьому застосунку. Для цього потрібно вказати, де він
надається (provided).
| Спосіб | Приклад | Пояснення |
| ------------------------------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| **1. Через `providedIn: 'root'`** | `@Injectable({ providedIn: 'root' })` | Найпоширеніший спосіб. Сервіс реєструється в головному інжекторі, створюється один раз для всього застосунку. |
| **2. Через модуль (deprecated підхід)** | Додати в `providers` масив модуля (`@NgModule`) | Використовується рідше. Сервіс буде singleton лише в межах цього модуля. |
| **3. Через компонент (локальний інжектор)** | Додати в `providers` масив компонента | Сервіс не буде singleton - створюється новий екземпляр для кожного компонента. |
#### Приклад:
```TypeScript
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**
```TypeScript
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class DataService {
private messageSource = new BehaviorSubject('Hello');
message$ = this.messageSource.asObservable();
updateMessage(newMsg: string) {
this.messageSource.next(newMsg);
}
}
```
**component-a.ts**
```TypeScript
@Component({...})
export class ComponentA {
constructor(private dataService: DataService) {}
sendMessage() {
this.dataService.updateMessage('Message from A');
}
}
```
**component-b.ts**
```TypeScript
@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` | Новий екземпляр для кожного екземпляра компонента | Для локального стану або ізольованої логіки. |
#### Приклад:
```TypeScript
@Injectable({
providedIn: 'root'
})
export class UserService {}
```
**або**
```TypeScript
@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`) | Сервіс буде створено лише в межах цього модуля. | Локальна. | Використовується для модульної ізоляції. |
#### Приклад:
```TypeScript
@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`. |
#### Приклад:
```TypeScript
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 {
return this.http.get(this.apiUrl);
}
addUser(user: User): Observable {
return this.http.post(this.apiUrl, user);
}
}
```
**component.ts**
```TypeScript
@Component({...})
export class AppComponent {
users$ = this.userService.getUsers();
constructor(private userService: UserService) {}
}
```
#### Особливості:
- `HttpClient` автоматично парсить JSON у JS-об’єкти.
- Можна вказати generic тип (``), щоб отримати типізовану відповідь.
- Повертає 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`, щоб компонент міг підписатися. |
#### Приклад:
```TypeScript
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 {
return this.http.get(this.apiUrl).pipe(
catchError(this.handleError)
);
}
addProduct(product: Product): Observable {
return this.http.post(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 | Додати `` у шаблон, щоб рендерити активний маршрут. |
| 4 | Використовувати директиви `[routerLink]` для навігації. |
#### Приклад (standalone routing):
**app.routes.ts**
```TypeScript
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**
```TypeScript
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**
```HTML
```
#### Додаткові можливості:
- **Route Guards** (`canActivate`, `canDeactivate`) - для захисту маршрутів.
- **Lazy Loading** - динамічне підвантаження модулів або компонентів.
- **Route Parameters** (`:id`) - для передачі динамічних значень у маршруті.
**Коротко:**
Маршрутизація в Angular конфігурується через масив `Routes` і `RouterModule` або
provideRouter(). Компоненти рендеряться у ``, а переходи
виконуються через `[routerLink]`.
30. Як у Angular створити маршрут, який динамічно завантажує модуль лише під час доступу до нього (lazy loading)?
#### Angular
Так, у сучасному Angular (v16–20) це робиться через **_lazy loading_** з
використанням динамічного `import()` у файлі маршрутизації. Це дозволяє не
включати модуль у основний bundle, а завантажувати його лише при навігації.
#### Приклад:
```TypeScript
// 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-компонентів:
```TypeScript
{
path: 'dashboard',
loadComponent: () =>
import('./dashboard/dashboard.component').then(c => c.DashboardComponent),
}
```
**Коротко:**
- `loadChildren` або `loadComponent` використовуються для lazy loading.
- Модуль/компонент завантажується лише при першому переході на відповідний
маршрут.
- Це оптимізує стартову швидкість застосунку.
31. Що таке RouterOutlet в Angular і як його використовують?
#### Angular
- `` - це директива, яка визначає місце у шаблоні, куди Angular
підставляє компонент, що відповідає активному маршруту. Вона є “контейнером”
для відображення контенту згідно з конфігурацією маршрутизатора.
#### Приклад:
```HTML
```
```TypeScript
// 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):
```TypeScript
// auth.guard.ts
import { CanActivateFn } from '@angular/router';
export const authGuard: CanActivateFn = (route, state) => {
const isLoggedIn = !!localStorage.getItem('token');
return isLoggedIn; // або redirectUrl при потребі
};
```
```TypeScript
// 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`. Використовується всередині компонентів для отримання контексту маршруту.
#### Приклад:
```TypeScript
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-user',
template: `
User ID: {{ userId }}
`})
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, які визначаються у маршрутах та
дозволяють передавати дані у компонент.
#### Приклад:
```TypeScript
// app.routes.ts
import { Routes } from '@angular/router';
import { UserComponent } from './user.component';
export const routes: Routes = [
{ path: 'user/:id', component: UserComponent },
];
```
```TypeScript
// user.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-user',
template: `
User ID: {{ userId }}
`})
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/123` → `id = 123`).
- Доступ через `ActivatedRoute.snapshot.paramMap` або
`ActivatedRoute.paramMap.subscribe()`.
- Використовуються для динамічного рендерингу контенту.
35. Як у Angular заздалегідь завантажити дані перед переходом на маршрут (resolve data)?
#### Angular
Для цього використовують **_Route Resolver_** - сервіс, який реалізує інтерфейс
`Resolve`. Angular чекає, поки resolver отримає дані, і передає їх у
компонент через `ActivatedRoute.data`.
#### Приклад:
```TypeScript
// 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 {
constructor(private userService: UserService) {}
resolve() {
return this.userService.getUser(); // може повертати Observable або Promise
}
}
```
```TypeScript
// 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 }
}
];
```
```TypeScript
// 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):
```TypeScript
// 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):
```TypeScript
{
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:**
```HTML
```
**Reactive:**
```TypeScript
form = new FormGroup({
email: new FormControl('', { nonNullable: true, validators: [Validators.required] })
});
```
```HTML
```
**Коротко:**
- Template-driven - декларативний підхід у шаблоні.
- Reactive - імперативний підхід у коді, з повним контролем над станом форми.
38. Як виконується валідація користувацького введення у формах Angular?
#### Angular
В Angular є вбудована, кастомна та асинхронна валідація. Валідація визначається
або через HTML-атрибути (у Template-driven формах), або через `Validators` у
Reactive формах.
**Reactive форма з валідацією:**
```TypeScript
form = new FormGroup({
email: new FormControl('', {
nonNullable: true,
validators: [Validators.required, Validators.email]
}),
password: new FormControl('', {
validators: [Validators.required, Validators.minLength(6)]
})
});
```
**HTML:**
```HTML
Invalid email
```
**Кастомний валідатор (приклад):**
```TypeScript
function forbiddenNameValidator(control: FormControl) {
return control.value === 'admin' ? { forbiddenName: true } : null;
}
```
**Асинхронний валідатор (приклад):**
```TypeScript
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:**
```TypeScript
form = new FormGroup({
users: new FormArray>([])
});
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:**
```HTML
Remove
Add User
```
**Коротко:**
- Використовуй FormArray для списків контролів.
- Використовуй `addControl()` / `removeControl()` у `FormGroup` для динамічних
окремих полів.
40. Що таке FormGroup у Angular і як він працює?
#### Angular
- `FormGroup` - це об’єкт, який об’єднує кілька `FormControl` або навіть інших
`FormGroup` у єдину структуру. Він дозволяє керувати станом, значеннями та
валідацією всієї групи як одного цілого.
**Ключові моменти:**
- `FormGroup` зберігає набір контролів у вигляді об’єкта.
- Дозволяє отримати стан (`valid`, `dirty`, `touched`) або значення (`value`)
всієї групи.
- Може мати групову валідацію (на рівні всієї форми).
**Приклад:**
```TypeScript
form = new FormGroup({ user: new FormGroup({ name: new FormControl('',
Validators.required), email: new FormControl('', Validators.email) }) });
```
**HTML:**
```HTML
```
**Коротко:**
- `FormGroup` = контейнер для контролів → дає змогу керувати групою полів як
єдиним об’єктом (для валідації, оновлення, сабміту).
41. Як створити власні (custom) валідатори у формах Angular?
#### Angular
Кастомний валідатор - це функція, яка приймає `FormControl` або
`AbstractControl` і повертає об’єкт помилки `{ [key: string]: any }` або `null`,
якщо помилок немає. Її можна використовувати в Reactive Forms або
Template-driven.
**Синхронний валідатор (приклад):**
```TypeScript
import { AbstractControl, ValidationErrors } from '@angular/forms';
export function forbiddenWordValidator(control: AbstractControl):
ValidationErrors | null { const forbidden = control.value?.toLowerCase() ===
'admin'; return forbidden ? { forbiddenWord: true } : null; }
```
**Використання:**
```TypeScript
form = new FormGroup({ username: new FormControl('', [forbiddenWordValidator])
});
```
**Асинхронний валідатор (приклад):**
```TypeScript
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. Це дозволяє відображати та керувати динамічними
наборами полів (наприклад, списком телефонів, тегів чи користувачів).
**Приклад:**
```TypeScript
form = new FormGroup({
phones: new FormArray>([
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:**
```HTML
Remove
Add Phone
```
**Коротко:**
- `formArrayName` - це директива для доступу до `FormArray` у шаблоні.
- Кожен елемент масиву - окремий FormControl або FormGroup.
- Використовується для динамічних форм, де кількість полів може змінюватися.
43. Як відправити дані форми з Angular-додатку на бекенд-сервіс?
#### Angular
- У Angular форма зазвичай відправляється через сервіс, який використовує
`HttpClient` для HTTP-запиту (`POST`, `PUT` тощо). Після сабміту зчитують
`form.value`, перевіряють `form.valid` і викликають метод сервісу.
**Приклад:**
```TypeScript
// user.service.ts
@Injectable({ providedIn: 'root' })
export class UserService {
constructor(private http: HttpClient) {}
submitUser(data: any) {
return this.http.post('/api/users', data);
}
}
```
```TypeScript
// 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:**
```HTML
Save
```
**Коротко:**
- Отримуєш `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, яка залежить від
сигналу.
2. **Standalone Components**
Менший бандл, швидший старт, немає модульних оверхедів.
3. **Lazy loading та route-level code splitting**
Завантажувати лише той код, який потрібен на даному маршруті.
4. **OnPush (для legacy компонентів без сигналів)**
Зменшує кількість викликів change detection у старих компонентах.
5. **trackBy у ngFor**
Запобігає перерендеру списків:
```HTML
```
6. **Оптимізація RxJS**
takeUntil, shareReplay, уникання непотрібних сабскрипцій.
7. **Async Pipe замість manual subscribe**
Запобігає memory leaks і зайвим CD-циклами.
8. **Оптимізація шаблону**
Мінімізувати важкі обчислення у template (винести в getters або signals).
9. **Preloading strategies**
Оптимізує навігацію між маршрутами (наприклад, PreloadAllModules або custom).
10. **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
```bash
ng add @angular/ssr
```
Автоматично створюється сервер, SSR bootstrap і hydration.
2. Bootstrap
**Browser**
```TypeScript
bootstrapApplication(AppComponent, appConfig);
```
**Server**
```TypeScript
export default () =>
bootstrapApplication(AppComponent, appConfig);
```
3. Hydration
```TypeScript
provideClientHydration()
```
Angular підхоплює HTML, а не рендерить заново.
4. Сервер (Node / Express)
```TypeScript
renderApplication(bootstrap, { url, document })
```
5. SSR-safe код
```TypeScript
isPlatformBrowser(PLATFORM_ID)
```
без window, document напряму
6. Дані
- API викликаємо **на сервері**
- Передаємо в браузер через `TransferState`
- Signals працюють з SSR без проблем
7. Коли використовувати
SEO, швидкий FCP
8. Коли не використовувати
Адмінки, 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-компонент.
```TypeScript
@Component({ selector: 'app-user', standalone: true, template: `{{ name }}` })
export class UserComponent { name = 'Viktor'; }
```
**@Directive**
Створює кастомну директиву (attribute або structural).
```TypeScript
@Directive({ selector: '[appHighlight]' }) export class HighlightDirective {}
```
**@Pipe**
Створює pipe для трансформації даних у шаблонах.
```TypeScript
@Pipe({ name: 'uppercase' }) export class UppercasePipe { transform(value:
string) { return value.toUpperCase(); } }
```
**@Injectable**
Позначає клас як сервіс для DI.
```TypeScript
@Injectable({ providedIn: 'root' }) export class UserService {}
```
2. Property decorators (взаємодія з шаблоном)
**@Input**
Передача даних у компонент.
```TypeScript
@Input() title!: string;
```
**@Output**
Передача подій з компонента.
```TypeScript
@Output() saved = new EventEmitter();
```
**@HostBinding**
Байндінг до властивостей host-елемента.
```TypeScript
@HostBinding('class.active') isActive = true;
```
**@HostListener**
Підписка на події host-елемента.
```TypeScript
@HostListener('click') onClick() {}
```
3. Dependency Injection decorators
**@Inject**
Явна інʼєкція залежності.
```TypeScript
constructor(@Inject(API_URL) private apiUrl: string) {}
```
**@Optional**
Залежність може бути відсутня.
```TypeScript
constructor(@Optional() private logger?: LoggerService) {}
```
**@Self**, **@SkipSelf**
Контроль області пошуку залежностей.
```TypeScript
constructor(@Self() private control: NgControl) {}
```
4. View / Content decorators
**@ViewChild** / **@ViewChildren**
Доступ до елементів власного шаблону.
```TypeScript
@ViewChild('input') input!: ElementRef;
```
**@ContentChild** / **@ContentChildren**
Доступ до проєктованого контенту (ng-content).
```TypeScript
@ContentChild(TemplateRef) tpl!: TemplateRef;
```
5. Стан у Angular 20+
- Декоратори **все ще підтримуються**
- Але часто замінюються:
- `inject()` замість constructor DI
- Signals замість `@Input` + `ngOnChanges`
- **Standalone API не скасовує декоратори**, лише спрощує архітектуру
50. Як реалізувати анімаційні переходи в Angular-додатку?
#### Angular
Angular має вбудовану систему анімацій через `@angular/animations`. У Angular
20+ використовую `provideAnimations()` у конфігурації:
```TypeScript
// app.config.ts
import { provideAnimations } from '@angular/platform-browser/animations';
export const appConfig: ApplicationConfig = {
providers: [provideAnimations()]
};
```
1. Анімація станів компонента
```TypeScript
typescriptimport { trigger, state, style, transition, animate } from '@angular/animations';
@Component({
template: `
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);
}
```
2. Анімація роутів
```TypeScript
// app.component.ts
@Component({
template: `
`,
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 })
])
])
]
})
```
3. Анімація списків (stagger)
```TypeScript
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
2. Attribute directive
**Приклад: директива підсвічування**
```TypeScript
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);
}
}
```
**Використання**
```HTML
Highlighted text
```
3. Structural directive
**Приклад: кастомний `*appIf`**
```TypeScript
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[appIf]',
standalone: true,
})
export class AppIfDirective {
constructor(
private tpl: TemplateRef,
private vcr: ViewContainerRef
) {}
@Input()
set appIf(condition: boolean) {
this.vcr.clear();
if (condition) {
this.vcr.createEmbeddedView(this.tpl);
}
}
}
```
**Використання**
```HTML
```
4. 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. Обʼєкт (найпоширеніше)
```HTML
```
2. Масив
```HTML
```
3. Рядок
```HTML
```
#### Best practices
- Використовуйте для умовної стилізації
- Працює ефективно з `ChangeDetectionStrategy.OnPush`
- Добре поєднується з signals
```TypeScript
isActive = signal(true);
```
#### `ngStyle`
Директива `ngStyle` використовується для динамічного задання inline-стилів.
#### Приклад
```HTML
```
```TypeScript
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-елемента.
```TypeScript
constructor(private el: ElementRef) {
this.el.nativeElement.focus();
}
```
**Недолік:** прямий доступ до DOM Не рекомендовано для SSR та безпеки
2. Renderer2 (рекомендовано)
Абстракція над DOM - безпечна та SSR-friendly.
```TypeScript
constructor(
private el: ElementRef,
private renderer: Renderer2
) {}
ngOnInit() {
this.renderer.setStyle(
this.el.nativeElement,
'background-color',
'yellow'
);
}
```
- Працює з SSR
- Безпечний (XSS)
- Кросплатформений
3. @HostBinding Біндінг до властивостей host-елемента.
```TypeScript
@HostBinding('class.active') isActive = true;
```
- Чисто
- Без прямого DOM-доступу
4. @HostListener
Підписка на події host-елемента.
```TypeScript
@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)
## Приклад використання
```TypeScript
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-операції напряму
2. SSR-friendly
- Працює коректно при Server-Side Rendering
- Не ламається через відсутність window / document
3. Абстракція над DOM
- Angular вирішує як саме застосувати зміни
- Підтримує різні платформи
4. Краща підтримка 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 для форматування імені
```TypeScript
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);
}
}
```
2. Використання в шаблоні
```HTML
{{ 'angular' | capitalize }}
```
3. Pure vs Impure pipes
**Pure pipe (за замовчуванням)**
- Викликається лише при зміні input
- Краща продуктивність
```TypeScript
@Pipe({ name: 'myPipe', pure: true })
```
**Impure pipe**
- Викликається на кожен change detection
- Використовувати обережно
```TypeScript
@Pipe({ name: 'myPipe', pure: false })
```
4. Pipe з параметрами
```TypeScript
@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;
}
}
```
```HTML
{{ text | truncate:20 }}
```
5. 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)
```TypeScript
@Pipe({
name: 'uppercase',
standalone: true,
pure: true, // default
})
export class UppercasePipe {}
```
#### Приклад використання
```HTML
{{ name | uppercase }}
```
#### Коли використовувати
- Форматування рядків
- Обчислення на основі immutable-даних
- 99% кейсів
#### Нечисті канали (Impure Pipes)
#### Характеристики
- Викликаються на кожен цикл change detection
- Не кешуються
- Значно гірша продуктивність
- Можуть мати side-effects (небажано)
```TypeScript
Копіювати код
@Pipe({
name: 'timeAgo',
standalone: true,
pure: false,
})
export class TimeAgoPipe {}
```
#### Приклад використання
```HTML
{{ timestamp | timeAgo }}
```
#### 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`
- автоматично оновлює шаблон при нових значеннях
- **сам відписуєт