Accessing Multiple Dynamically Generated Component References Using @ViewChildren in Angular

Dec 02, 2025 · Programming · 7 views · 7.8

Keywords: Angular | @ViewChildren | QueryList | Component Communication | Dynamic Components

Abstract: This article provides an in-depth exploration of how to effectively obtain references to components that are dynamically generated via the *ngFor directive in the Angular framework. While the traditional @ViewChild decorator is suitable only for single static components, @ViewChildren combined with QueryList offers a robust solution for handling collections of dynamic components. The paper thoroughly analyzes the working principles of @ViewChildren, the API characteristics of QueryList, and demonstrates best practices for safely accessing component references within the ngAfterViewInit lifecycle hook through practical code examples. Additionally, it compares two query approaches—based on template reference variables and component classes—providing developers with a comprehensive technical guide for managing dynamic UI component communication.

In Angular application development, inter-component communication is one of the core design patterns. When a parent component needs to access the properties or methods of child components, the @ViewChild decorator is typically used to obtain a reference to a single component. However, in real-world development scenarios, components are often dynamically generated via structural directives like *ngFor, and their quantity may vary at runtime. In such cases, the limitation of @ViewChild becomes apparent—it can only return the reference to the first matching component and cannot handle multiple instances.

Fundamental Principles of @ViewChildren and QueryList

Angular provides the @ViewChildren decorator as an extension of @ViewChild, specifically designed for querying multiple view child elements. Its core mechanism involves collecting all matching component or directive instances after component view initialization through the dependency injection system and encapsulating them in a QueryList object. QueryList is an observable collection class that offers practical methods such as toArray(), forEach(), and length, supporting traversal and manipulation of dynamically changing component collections.

Implementation of Queries Based on Template Reference Variables

When child components define reference variables in the template, queries can be performed using variable names. The following example demonstrates adding a #cmp reference to each <customcomponent> within an *ngFor loop and obtaining all instances in the parent component:

<div *ngFor="let v of views">
    <customcomponent #cmp></customcomponent>
</div>

In the component class, declare the query using @ViewChildren('cmp'):

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

@Component({
    selector: 'app-parent',
    templateUrl: './parent.component.html'
})
export class ParentComponent implements AfterViewInit {
    @ViewChildren('cmp') components: QueryList<CustomComponent>;

    ngAfterViewInit() {
        // Convert QueryList to an array
        const componentArray = this.components.toArray();
        console.log('Number of components:', componentArray.length);
        
        // Iterate over all component instances
        this.components.forEach((child, index) => {
            console.log(`Component ${index}:`, child);
            // Child component methods or properties can be accessed here
        });
    }
}

Query Approach Based on Component Classes

In addition to template reference variables, @ViewChildren also supports direct queries via component classes. This approach does not require explicit declaration of reference variables in the template, resulting in more concise code:

@ViewChildren(CustomComponent) customComponentChildren: QueryList<CustomComponent>;

This query method matches all component instances of type CustomComponent in the template, regardless of whether they have reference variables. In practice, batch processing can be performed using the forEach method:

this.customComponentChildren.forEach((child) => {
    child.someProperty = 'modified value';
    child.someMethod();
});

Lifecycle and Query Timing

A critical design consideration is the timing of query execution. The results of @ViewChildren queries are not available until the ngAfterViewInit lifecycle hook. This is because Angular needs to complete the initial rendering of the view to establish a complete component tree. Accessing QueryList in ngOnInit or the constructor will yield empty results or an uninitialized state.

QueryList also provides change detection support. When child components are dynamically added or removed, QueryList automatically updates its contents. Developers can respond to these changes by subscribing to the changes observable:

ngAfterViewInit() {
    this.components.changes.subscribe((changeList: QueryList<CustomComponent>) => {
        console.log('Component list updated, new count:', changeList.length);
        // Handle added or removed components
    });
}

Practical Application Scenarios and Best Practices

This pattern holds significant value in various practical scenarios: in form validation, where a parent component needs to collect validation states from all child form components; in data dashboards, where multiple visualization components require unified updates to display parameters; and in list management, where batch operations on multiple list item components are necessary.

Best practices include: always accessing QueryList within ngAfterViewInit; using typed QueryList<T> to ensure type safety; considering performance impacts by avoiding expensive query operations within change detection cycles; and for large component collections, optimizing *ngFor performance with a trackBy function.

Unlike approaches using ElementRef to directly manipulate the DOM, @ViewChildren maintains Angular's abstraction level by interacting through component interfaces, aligning with Angular's component-based design philosophy. Additionally, in contrast to @ContentChildren queries for projected content, @ViewChildren specifically handles direct view child elements, with clear distinctions in application scenarios.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.