Και οι δύο δίνουν ερωτήματα για αναφορές σε στοιχεία/συστατικά θυγατρικών, αλλά αναζητούν σε διαφορετικά σημεία: @ViewChild δίνει ερώτημα στο , ενώ δίνει ερώτημα στο περιεχόμενο το συστατικό μέσω .
Και οι δύο δίνουν ερωτήματα για αναφορές σε στοιχεία/συστατικά θυγατρικών, αλλά αναζητούν σε διαφορετικά σημεία: @ViewChild δίνει ερώτημα στο , ενώ δίνει ερώτημα στο περιεχόμενο το συστατικό μέσω .
@ContentChild<ng-content>@Component({
template: `
<input #nameInput /> <!-- a template reference in MY template -->
<app-child></app-child>
`,
})
export class ParentComponent implements AfterViewInit {
@ViewChild("nameInput") input!: ElementRef; // by template ref
@ViewChild(ChildComponent) child!: ChildComponent; // by component type
ngAfterViewInit() {
this.input.nativeElement.focus(); // available after the VIEW initializes
this.child.doSomething(); // call a child component's method
}
}
@ViewChild έχει πρόσβαση σε στοιχεία/συστατικά που το ίδιο το συστατικό δηλώνει στο πρότυπό του — διαθέσιμο στο ngAfterViewInit.
@Component({
selector: "app-card",
template: `<div class="card"><ng-content></ng-content></div>`, // content projected here
})
export class CardComponent implements AfterContentInit {
@ContentChild(CardTitleComponent) title!: CardTitleComponent;
ngAfterContentInit() {
// the projected content is ready here (EARLIER than ngAfterViewInit)
console.log(this.title);
}
}
<!-- parent projects content INTO app-card -->
<app-card>
<app-card-title>Hello</app-card-title> <!-- this is what ContentChild finds -->
</app-card>
@ContentChild έχει πρόσβαση στο περιεχόμενο που πέρασε το γονικό συστατικό (προβάλλεται μέσω <ng-content>) — διαθέσιμο στο ngAfterContentInit.
@ViewChild → elements in THIS component's own template → ngAfterViewInit
@ContentChild → elements PROJECTED in from the parent → ngAfterContentInit
(plural: @ViewChildren / @ContentChildren return a QueryList of all matches)
@ViewChildren(ItemComponent) items!: QueryList<ItemComponent>; // all matching items
ngAfterViewInit() { this.items.forEach(i => ...); this.items.changes.subscribe(...); }
input = viewChild<ElementRef>("nameInput"); // signal-based query (newer Angular)
Η διάκριση μεταξύ @ViewChild (το πρότυπό σου) και @ContentChild (προβληθέν περιεχόμενο) — και των αντίστοιχων χρονισμών κύκλου ζωής τους (ngAfterViewInit vs ngAfterContentInit) — είναι απαραίτητη κατά την δημιουργία επαναχρησιμοποιήσιμων συστατικών που πρέπει να αλληλεπιδράσουν είτε με τα δικά τους στοιχεία προτύπων είτε με το περιεχόμενο που προβάλλουν οι καταναλωτές σε αυτά.
Είναι ένα συνηθισμένο σημείο σύγχυσης και μια συχνή ανάγκη κατά τη σύνταξη βιβλιοθηκών συστατικών, καρτών, στοιχείων ελέγχου φορμών και wrapper που πρέπει να συντονιστούν με θυγατρικά στοιχεία.