Performance: @ContentChild and content projection
This concept affects rendering speed and interaction responsiveness by how Angular queries and projects DOM nodes inside components.
import { Component, ContentChild, AfterContentInit, ElementRef } from '@angular/core'; @Component({ selector: 'good-projection', template: `<ng-content></ng-content>` }) export class GoodProjectionComponent implements AfterContentInit { @ContentChild('projectedRef', { static: false }) projectedElement!: ElementRef; ngAfterContentInit() { const el = this.projectedElement.nativeElement; const height = el.offsetHeight; const width = el.offsetWidth; console.log(height, width); } }
import { Component, ContentChild, AfterContentInit, ElementRef } from '@angular/core'; @Component({ selector: 'bad-projection', template: `<ng-content></ng-content>` }) export class BadProjectionComponent implements AfterContentInit { @ContentChild('projectedRef', { static: false }) projectedElement!: ElementRef; ngAfterContentInit() { // Accessing nativeElement multiple times console.log(this.projectedElement.nativeElement.offsetHeight); console.log(this.projectedElement.nativeElement.offsetWidth); } }
| Pattern | DOM Operations | Reflows | Paint Cost | Verdict |
|---|---|---|---|---|
| Multiple nativeElement reads in ngAfterContentInit | Single query, multiple property reads | 2 reflows | Medium paint cost | [X] Bad |
| Single nativeElement read cached in variable | Single query, single property read | 1 reflow | Low paint cost | [OK] Good |
| @ContentChild query in ngAfterContentChecked | Multiple queries per cycle | Multiple reflows | High paint cost | [X] Bad |
| @ContentChild query in ngAfterContentInit only | Single query | 1 reflow | Low paint cost | [OK] Good |
@ContentChild do in a component?<ng-content>.@ContentChild to get a reference to a template variable named myRef?@Component({ selector: 'child-comp', template: `` })
export class ChildComp {
@ContentChild('proj') projElement!: ElementRef;
ngAfterContentInit() {
console.log(this.projElement.nativeElement.textContent);
}
}Hello World
<p #proj> is projected inside <ng-content>. @ContentChild('proj') gets its reference.projElement is defined and accessible.@Component({ selector: 'proj-comp', template: `` })
export class ProjComp {
@ContentChild('item') itemRef!: ElementRef;
ngOnInit() {
console.log(this.itemRef.nativeElement.textContent);
}
}Test
@ContentChildren('para') and highlight the first in the list.@ContentChild('para') and add #para to the first paragraph only.@ViewChild('para') inside the component template.@ContentChild without a selector and highlight all paragraphs.Pass the test and this pattern moves unknown