ViewChild та ContentChild в Angular
ViewChild та ContentChild
@ViewChild та @ContentChild — це декоратори, які надають вам програмний доступ до дочірніх елементів, компонентів або директив у вашому шаблоні.
@ViewChild — Доступ до елементів шаблону
Доступ до елементів, визначених у власному шаблоні компонента:
typescript
@Component({
template: \`
<input #nameInput type="text">
<app-chart #chart [data]="chartData"></app-chart>
<button (click)="focusInput()">Фокус</button>
\`
})
export class MyComponent implements AfterViewInit {
@ViewChild('nameInput') inputEl!: ElementRef<HTMLInputElement>;
@ViewChild('chart') chartComponent!: ChartComponent;
ngAfterViewInit() {
// Доступно після ініціалізації виду
this.inputEl.nativeElement.focus();
this.chartComponent.refresh();
}
focusInput() {
this.inputEl.nativeElement.focus();
}
}@ViewChildren — Багато елементів
typescript
@Component({
template: \`
<app-tab *ngFor="let tab of tabs" [title]="tab.title">
{{ tab.content }}
</app-tab>
\`
})
export class TabsComponent implements AfterViewInit {
@ViewChildren(TabComponent) tabComponents!: QueryList<TabComponent>;
ngAfterViewInit() {
this.tabComponents.forEach(tab => console.log(tab.title));
// Реакція на зміни (коли *ngFor додає/видаляє елементи)
this.tabComponents.changes.subscribe(tabs => {
console.log('Вкладки змінено:', tabs.length);
});
}
}@ContentChild — Доступ до проекційного контенту
Доступ до елементів, проектованих у компонент через <ng-content>:
typescript
@Component({
selector: 'app-panel',
template: \`
<div class="panel">
<ng-content></ng-content>
</div>
\`
})
export class PanelComponent implements AfterContentInit {
@ContentChild('panelTitle') titleEl!: ElementRef;
@ContentChild(ButtonComponent) button!: ButtonComponent;
ngAfterContentInit() {
// Доступно після ініціалізації контенту
console.log(this.titleEl?.nativeElement.textContent);
}
}html
<!-- Шаблон батька -->
<app-panel>
<h2 #panelTitle>Моя панель</h2>
<app-button>Натисніть на мене</app-button>
</app-panel>ViewChild проти ContentChild
| Особливість | @ViewChild | @ContentChild |
|---|---|---|
| Доступає до | Власного шаблону компонента | Проектованого контенту (ng-content) |
| Життєвий цикл | ngAfterViewInit | ngAfterContentInit |
| Багато | @ViewChildren | @ContentChildren |
| Визначено в | Шаблоні компонента | Шаблоні батька (проектований) |
Запити сигналів (Angular 17+)
typescript
@Component({ /* ... */ })
export class MyComponent {
// Запити на основі сигналів (сучасні)
nameInput = viewChild.required<ElementRef>('nameInput');
chart = viewChild(ChartComponent);
tabs = viewChildren(TabComponent);
// Запити контенту
title = contentChild<ElementRef>('title');
buttons = contentChildren(ButtonComponent);
}Опція Read
typescript
// Читати як ElementRef замість екземпляра компонента
@ViewChild('myComp', { read: ElementRef }) el!: ElementRef;
// Читати ViewContainerRef (для динамічних компонентів)
@ViewChild('container', { read: ViewContainerRef }) container!: ViewContainerRef;Важливо:
@ViewChild отримує доступ до елементів у власному шаблоні компонента (доступно в ngAfterViewInit). @ContentChild отримує доступ до проектованого контенту (доступно в ngAfterContentInit). В Angular 17+ віддавайте перевагу запитам на основі сигналів (viewChild(), contentChild()). Використовуйте QueryList.changes, щоб реагувати на зміни динамічного контенту.
Коротка відповідь
Для співбесідиPremium
Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.