The magic of ContentChild, ViewChild and Template References
In Angular we tend to write declarative code. This means we are not supposed to manually query things when we need them. There are instruments in the framework that allow us to do so. First, lets recap what content and view mean.

View is template of your component. This means it doesn’t exist in directives.
Content is what your component (or directive) is wrapped around. For components you need to add ng‑content tag in your view to preserve content. Otherwise it is replaced with view upon render.
💡 Performance tip: even if
ng‑contentis hidden with*ngIfand detached from DOM, it is still rendered. And it still goes through change detection cycles. If you need lazy content initialization you need to use templates.
ViewChild and ViewChildren
When you create component, you might need access to some parts of its template. @ViewChild decorator allows you to do so and more. First, you need to provide selector. You can mark item with a string in the template: <div #ref>...</div>. And then query it with a decorator: @ViewChild('ref')
This is a template reference variable and we will discuss it in detail later.
It could also be class if you aim at a component or a directive: @ViewChild(MyComponent)
It can even be an injection token: @ViewChild(MY_TOKEN)
Real strength though comes with the second argument — an options object. First option is trivial: static: boolean. It tells Angular whether some child always exists or present with a condition. static: true means it can be queried in ngOnInit. static: false means it is not available until ngAfterViewInit. Default value is false.
<div #static>
I'm a static child
</div>
<div *ngIf="true" #dynamic>
I'm not a static child
</div>Note that even static queries are resolved only in
ngOnInit. So technically they areundefinedfor some time. It is a good practice to reflect that with proper type so you do not try to accidentally access it in a constructor. Hence a question mark in type in examples above.
Second option is read. First argument tells Angular where to look and read tells it what to look for. We can get everything from target injector - be it a service, a token or a component instance.
By default, @ViewChild retrieves a component when we query it. The most common use for read option is to get ElementRef instead:
@ViewChild(MyComponent, { read: ElementRef })
readonly elementRef?: ElementRef<HTMLElement>Quite often though you don’t need @ViewChild at all. In a lot of cases you can just use template reference variable and pass it straight to the callback:
<input #input type="text" [(ngModel)]="model">
<button (click)="onClick(input)">Focus input</button>"// Notice that it's HTMLElement not ElementRef here in this case
onClick(element: HTMLElement) {
element.focus();
}You can think of template reference variables as kind of closures in template in this case. The reference is there, but it only exists in a closed circuit where it is needed. It helps you keep component’s code clean.
Template reference variable targets component when it’s on one and an HTML element when it’s not. It can also target directives, that’s what exportAs is for in @Directive decorator:
@Directive({
selector: '[myDirective]',
exportAs: 'someName',
})
export class MyDirective {}<div myDirective #ref="someName">...</div>Sometimes you need to query multiple items of the same kind. In this case you can use @ViewChildren. You can mark many items in template with the same reference and retrieve a whole collection. All advices above are applicable here too, except the type would be QueryList<T> and static is not available for lists. This allows you to go over every item when you need to. Consider an example with tabs component. Instead of horizontal scroll you want to hide extra tabs into "More" button. See the demo below utilizing @ViewChildren to do the job:






