Что такое ViewChild и ContentChild?
ViewChild и ContentChild — это декораторы в Angular, позволяющие получить доступ к DOM-элементам, компонентам или директивам внутри шаблона компонента. Они используются для получения ссылок на дочерние элементы, чтобы программно взаимодействовать с ними (например, вызвать методы, изменить состояние или получить доступ к DOM).
@ViewChild
Что делает
Позволяет получить доступ к элементу из собственного шаблона компонента (то есть внутри <template> текущего компонента).
Когда применяется
-
Для получения ссылки на DOM-элемент.
-
Для доступа к экземпляру дочернего компонента или директивы.
-
Для доступа к TemplateRef или ViewContainerRef.
Когда доступен
ViewChild доступен после инициализации вьюхи — в ngAfterViewInit().
Синтаксис
@ViewChild('templateVar') elementRef!: ElementRef;
Или:
@ViewChild(ChildComponent) child!: ChildComponent;
Пример 1: DOM-элемент
<input #myInput />
@ViewChild('myInput') inputElement!: ElementRef;
ngAfterViewInit() {
this.inputElement.nativeElement.focus();
}
Пример 2: Дочерний компонент
<app-child #childRef></app-child>
@ViewChild('childRef') childComponent!: ChildComponent;
ngAfterViewInit() {
this.childComponent.someMethod();
}
Пример 3: По типу компонента
@ViewChild(ChildComponent) childComponent!: ChildComponent;
Это удобно, если в шаблоне есть только один компонент такого типа.
@ViewChildren
Если нужно получить несколько компонентов или элементов:
@ViewChildren(ChildComponent) children!: QueryList<ChildComponent>;
ngAfterViewInit() {
this.children.forEach(child => child.someMethod());
}
@ContentChild
Что делает
Позволяет получить доступ к контенту, переданному через ng-content из родительского компонента.
Когда применяется
-
Для доступа к элементам, переданным в <ng-content>.
-
Используется в компонентах, которые реализуют контентную проекцию.
Когда доступен
ContentChild доступен после ngAfterContentInit().
Синтаксис
@ContentChild(ChildDirective) childDirective!: ChildDirective;
Или:
@ContentChild('projectedRef') template!: TemplateRef<any>;
Пример: Контентная проекция
Родительский компонент:
<app-wrapper>
<p #projected>Hello</p>
</app-wrapper>
Компонент с проекцией:
<ng-content></ng-content>
@ContentChild('projected') content!: ElementRef;
ngAfterContentInit() {
console.log(this.content.nativeElement.textContent); // "Hello"
}
Отличие ViewChild и ContentChild
Характеристика | ViewChild | ContentChild |
---|---|---|
Что ищет | Внутри собственного шаблона компонента | Внутри <ng-content> — проецируемый контент |
--- | --- | --- |
Когда становится доступен | После ngAfterViewInit() | После ngAfterContentInit() |
--- | --- | --- |
Тип доступа | DOM, компонент, директива | DOM, компонент, директива |
--- | --- | --- |
Контекст поиска | Внутри текущего компонента | Внутри контента, переданного снаружи |
--- | --- | --- |
Почему важно вызывать в нужных lifecycle hooks
-
@ViewChild — не следует обращаться к элементу в ngOnInit, потому что шаблон еще не отрисован. Используйте ngAfterViewInit.
-
@ContentChild — используйте в ngAfterContentInit, чтобы быть уверенным, что контент уже вставлен в DOM.
Пример полного использования
@Component({
selector: 'app-child',
template: \`<p>Child component</p>\`
})
export class ChildComponent {
sayHello() {
console.log('Hello from child');
}
}
@Component({
selector: 'app-parent',
template: \`
<app-child #viewRef></app-child>
<ng-content></ng-content>
\`
})
export class ParentComponent implements AfterViewInit, AfterContentInit {
@ViewChild('viewRef') viewChild!: ChildComponent;
@ContentChild('contentRef') contentChild!: ElementRef;
ngAfterViewInit() {
this.viewChild.sayHello();
}
ngAfterContentInit() {
console.log(this.contentChild.nativeElement.textContent);
}
}
Модификаторы и параметры
-
{ static: true } — нужен, если вы хотите получить доступ к ViewChild/ContentChild в ngOnInit.
-
Обычно используется, если элемент не зависит от *ngIf, *ngFor и других структурных директив.
-
Если зависит — используйте { static: false }.
-
Пример:
@ViewChild('el', { static: true }) element!: ElementRef;
Частые ошибки
-
Использование @ViewChild до ngAfterViewInit (например, в constructor или ngOnInit) — объект будет undefined.
-
Ожидание, что @ContentChild найдет элемент, который на самом деле является частью шаблона — тогда нужно использовать @ViewChild.
-
Отсутствие #templateRef в шаблоне, когда указана ссылка по строке.
-
Неправильная установка static: true/false.
@ViewChild и @ContentChild дают точный контроль над DOM и дочерними компонентами, особенно в компонентах с динамической логикой, библиотечных компонентах и при работе с ng-content. Их правильное использование требует знания архитектуры компонента и понимания порядка инициализации шаблона.