← Назад к вопросам

Что такое ViewChildren?

2.0 Middle🔥 101 комментариев
#JavaScript Core

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое ViewChildren?

ViewChildren — это декоратор в Angular, который используется для получения доступа к коллекции дочерних элементов, компонентов или директив из шаблона (View) текущего компонента. Это один из ключевых механизмов взаимодействия между компонентами и их содержимым в Angular, работающий через систему запросов (queries).

Основная цель ViewChildren — позволить родительскому компоненту динамически взаимодействовать с дочерними элементами, которые определены в его шаблоне. Это особенно полезно, когда нужно:

  • Обращаться к нескольким однотипным элементам (например, всем инпутам в форме).
  • Вызывать методы или получать доступ к свойствам дочерних компонентов.
  • Реагировать на изменения в коллекции дочерних элементов.

Ключевые особенности ViewChildren

  1. Работает с элементами View (шаблона): ViewChildren запрашивает только те элементы, которые напрямую присутствуют в шаблоне текущего компонента (не включая контент, спроецированный через <ng-content> — для этого используется ContentChildren).

  2. Возвращает QueryList: Декоратор возвращает экземпляр QueryList, который является "живой" коллекцией. Он автоматически обновляется при добавлении, удалении или перемещении дочерних элементов (например, с помощью ngFor). QueryList предоставляет методы для итерации (forEach, map) и отслеживания изменений (changes).

  3. Доступ после инициализации View: Данные становятся доступными после срабатывания хука ngAfterViewInit. Попытка доступа раньше (например, в ngOnInit) вернёт пустую коллекцию.

  4. Поддерживает селекторы: Запрос может осуществляться по:

    • Типу компонента/директивы (например, ChildComponent).
    • Строковому селектору (например, 'div', '.my-class').
    • Ссылочной переменной шаблона (например, #myRef).

Примеры использования

Пример 1: Запрос дочерних компонентов

Допустим, у нас есть родительский компонент, содержащий несколько экземпляров ChildComponent.

import { Component, ViewChildren, QueryList, AfterViewInit } from '@angular/core';
import { ChildComponent } from './child.component';

@Component({
  selector: 'app-parent',
  template: `
    <app-child #child1></app-child>
    <app-child #child2></app-child>
    <button (click)="highlightChildren()">Highlight All</button>
  `
})
export class ParentComponent implements AfterViewInit {
  @ViewChildren(ChildComponent) children: QueryList<ChildComponent>;

  ngAfterViewInit() {
    console.log('Number of children:', this.children.length);
  }

  highlightChildren() {
    this.children.forEach(child => child.highlight());
  }
}

Пример 2: Запрос по ссылочной переменной

Можно запросить элементы DOM или директивы, используя локальные переменные шаблона.

import { Component, ViewChildren, QueryList, ElementRef } from '@angular/core';

@Component({
  selector: 'app-sample',
  template: `
    <input #inputRef placeholder="Enter text">
    <div #divRef class="item">Item 1</div>
    <div #divRef class="item">Item 2</div>
  `
})
export class SampleComponent {
  @ViewChildren('inputRef') inputs: QueryList<ElementRef>;
  @ViewChildren('divRef') divs: QueryList<ElementRef>;

  focusInput() {
    if (this.inputs.first) {
      this.inputs.first.nativeElement.focus();
    }
  }

  logDivs() {
    this.divs.forEach(div => console.log(div.nativeElement.textContent));
  }
}

Пример 3: Реакция на изменения коллекции

QueryList.changes возвращает Observable, на который можно подписаться для отслеживания динамических изменений.

import { Component, ViewChildren, QueryList, AfterViewInit, OnDestroy } from '@angular/core';
import { ChildComponent } from './child.component';
import { Subscription } from 'rxjs';

@Component({
  selector: 'app-dynamic',
  template: `
    <button (click)="addChild()">Add Child</button>
    <app-child *ngFor="let item of items"></app-child>
  `
})
export class DynamicComponent implements AfterViewInit, OnDestroy {
  items = [1, 2, 3];
  private subscription: Subscription;

  @ViewChildren(ChildComponent) children: QueryList<ChildComponent>;

  ngAfterViewInit() {
    this.subscription = this.children.changes.subscribe((list: QueryList<ChildComponent>) => {
      console.log('Children changed, new count:', list.length);
    });
  }

  addChild() {
    this.items.push(this.items.length + 1);
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}

Отличие от ContentChildren

Важно не путать ViewChildren с ContentChildren:

  • ViewChildren — запрашивает элементы, которые являются непосредственной частью шаблона компонента.
  • ContentChildren — запрашивает элементы, которые были спроецированы (проектированы) в компонент извне через <ng-content> (контентное проецирование).

Например, если компонент AppComponent использует <app-parent><app-child></app-child></app-parent>, то для ParentComponent дочерний элемент будет контентом, а не view.

Практические сценарии применения

  • Управление фокусом в динамически генерируемых полях формы.
  • Вызов методов API у всех дочерних компонентов (например, validate() для каждого поля).
  • Синхронизация состояния между несколькими экземплярами компонентов.
  • Интеграция со сторонними библиотеками, требующими доступа к DOM-элементам (через ElementRef).

Таким образом, ViewChildren — это мощный инструмент для декларативного взаимодействия с дочерними элементами шаблона в Angular, обеспечивающий реактивное обновление и гибкость в управлении DOM. Его правильное использование значительно упрощает разработку сложных компонентных интерфейсов.