In-depth Guides
Components

Referencing component children with queries

Tip: This guide assumes you've already read the Essentials Guide. Read that first if you're new to Angular.

A component can define queries that find child elements and read values from their injectors.

Developers most commonly use queries to retrieve references to child components, directives, DOM elements, and more.

There are two categories of query: view queries and content queries.

View queries

View queries retrieve results from the elements in the component's view — the elements defined in the component's own template. You can query for a single result with the @ViewChild decorator.

      
@Component({
selector: 'custom-card-header',
...
})
export class CustomCardHeader {
text: string;
}
@Component({
selector: 'custom-card',
template: '<custom-card-header>Visit sunny California!</custom-card-header>',
})
export class CustomCard {
@ViewChild(CustomCardHeader) header: CustomCardHeader;
ngAfterViewInit() {
console.log(this.header.text);
}
}

In this example, the CustomCard component queries for a child CustomCardHeader and accesses the result in ngAfterViewInit.

If the query does not find a result, its value is undefined. This may occur if the target element is hidden by NgIf. Angular keeps the result of @ViewChild up to date as your application state changes.

View query results become available in the ngAfterViewInit lifecycle method. Before this point, the value is undefined. See the Lifecycle section for details on the component lifecycle.

You can also query for multiple results with the @ViewChildren decorator.

      
@Component({
selector: 'custom-card-action',
...,
})
export class CustomCardAction {
text: string;
}
@Component({
selector: 'custom-card',
template: `
<custom-card-action>Save</custom-card-action>
<custom-card-action>Cancel</custom-card-action>
`,
})
export class CustomCard {
@ViewChildren(CustomCardAction) actions: QueryList<CustomCardAction>;
ngAfterViewInit() {
this.actions.forEach(action => {
console.log(action.text);
});
}
}

@ViewChildren creates a QueryList object that contains the query results. You can subscribe to changes to the query results over time via the changes property.

Queries never pierce through component boundaries. View queries can only retrieve results from the component's template.

Content queries

Content queries retrieve results from the elements in the component's content— the elements nested inside the component in the template where it's used. You can query for a single result with the @ContentChild decorator.

      
@Component({
selector: 'custom-toggle',
...
})
export class CustomToggle {
text: string;
}
@Component({
selector: 'custom-expando',
...
})
export class CustomExpando {
@ContentChild(CustomToggle) toggle: CustomToggle;
ngAfterContentInit() {
console.log(this.toggle.text);
}
}
@Component({
selector: 'user-profile',
template: `
<custom-expando>
<custom-toggle>Show</custom-toggle>
</custom-expando>
`
})

In this example, the CustomExpando component queries for a child CustomToggle and accesses the result in ngAfterContentInit.

If the query does not find a result, its value is undefined. This may occur if the target element is absent or hidden by NgIf. Angular keeps the result of @ContentChild up to date as your application state changes.

By default, content queries find only direct children of the component and do not traverse into descendants.

Content query results become available in the ngAfterContentInit lifecycle method. Before this point, the value is undefined. See the Lifecycle section for details on the component lifecycle.

You can also query for multiple results with the @ContentChildren decorator.

      
@Component({
selector: 'custom-menu-item',
...
})
export class CustomMenuItem {
text: string;
}
@Component({
selector: 'custom-menu',
...,
})
export class CustomMenu {
@ContentChildren(CustomMenuItem) items: QueryList<CustomMenuItem>;
ngAfterContentInit() {
this.items.forEach(item => {
console.log(item.text);
});
}
}
@Component({
selector: 'user-profile',
template: `
<custom-menu>
<custom-menu-item>Cheese</custom-menu-item>
<custom-menu-item>Tomato</custom-menu-item>
</custom-menu>
`
})

@ContentChildren creates a QueryList object that contains the query results. You can subscribe to changes to the query results over time via the changes property.

Queries never piece through component boundaries. Content queries can only retrieve results from the same template as the component itself.

Query locators

This first parameter for each query decorator is its locator.

Most of the time, you want to use a component or directive as your locator.

You can alternatively specify a string locator corresponding to a template reference variable.

      
@Component({
...,
template: `
<button #save>Save</button>
<button #cancel>Cancel</button>
`
})
export class ActionBar {
@ViewChild('save') saveButton: ElementRef<HTMLButtonElement>;
}

If more than one element defines the same template reference variable, the query retrieves the first matching element.

Angular does not support CSS selectors as query locators.

Queries and the injector tree

Tip: See Dependency Injection for background on providers and Angular's injection tree.

For more advanced cases, you can use any ProviderToken as a locator. This lets you locate elements based on component and directive providers.

      
const SUB_ITEM = new InjectionToken<string>('sub-item');
@Component({
...,
providers: [{provide: SUB_ITEM, useValue: 'special-item'}],
})
export class SpecialItem { }
@Component({...})
export class CustomList {
@ContentChild(SUB_ITEM) subItemType: string;
}

The above example uses an InjectionToken as a locator, but you can use any ProviderToken to locate specific elements.

Query options

All query decorators accept an options object as a second parameter. These options control how the query finds its results.

Static queries

@ViewChild and @ContentChild queries accept the static option.

      
@Component({
selector: 'custom-card',
template: '<custom-card-header>Visit sunny California!</custom-card-header>',
})
export class CustomCard {
@ViewChild(CustomCardHeader, {static: true}) header: CustomCardHeader;
ngOnInit() {
console.log(this.header.text);
}
}

By setting static: true, you guarantee to Angular that the target of this query is always present and is not conditionally rendered. This makes the result available earlier, in the ngOnInit lifecycle method.

Static query results do not update after initialization.

The static option is not available for @ViewChildren and @ContentChildren queries.

Content descendants

By default, content queries find only direct children of the component and do not traverse into descendants.

      
@Component({
selector: 'custom-expando',
...
})
export class CustomExpando {
@ContentChild(CustomToggle) toggle: CustomToggle;
}
@Component({
selector: 'user-profile',
template: `
<custom-expando>
<some-other-component>
<!-- custom-toggle will not be found! -->
<custom-toggle>Show</custom-toggle>
</some-other-component>
</custom-expando>
`
})

In the example above, CustomExpando cannot find <custom-toggle> because it is not a direct child of <custom-expando>. By setting descendants: true, you configure the query to traverse all descendants in the same template. Queries, however, never pierce into components to traverse elements in other templates.

View queries do not have this option because they always traverse into descendants.

Reading specific values from an element's injector

By default, the query locator indicates both the element you're searching for and the value retrieved. You can alternatively specify the read option to retrieve a different value from the element matched by the locator.

      
@Component({...})
export class CustomExpando {
@ContentChild(ExpandoContent, {read: TemplateRef}) toggle: TemplateRef;
}

The above example, locates an element with the directive ExpandoContent and retrieves the TemplateRef associated with that element.

Developers most commonly use read to retrieve ElementRef and TemplateRef.

Using QueryList

@ViewChildren and @ContentChildren both provide a QueryList object that contains a list of results.

QueryList offers a number of convenience APIs for working with results in an array-like manner, such as map, reduce, and forEach. You can get an array of the current results by calling toArray.

You can subscribe to the changes property to do something any time the results change.

Common query pitfalls

When using queries, common pitfalls can make your code harder to understand and maintain.

Always maintain a single source of truth for state shared between multiple components. This avoids scenarios where repeated state in different components becomes out of sync.

Avoid directly writing state to child components. This pattern can lead to brittle code that is hard to understand and is prone to ExpressionChangedAfterItHasBeenChecked errors.

Never directly write state to parent or ancestor components. This pattern can lead to brittle code that is hard to understand and is prone to ExpressionChangedAfterItHasBeenChecked errors.